SpringSecurity笔记【b站编程不良人】

目录

权限管理

认证

授权

整体架构

认证

Authentication 

SecurityContextHolder

springboot整合springsecurity

流程分析

默认⽤户⽣成

总结


权限管理

基本上涉及到⽤户参与的系统都要进⾏权限管理,权限管理属于系统安全的范畴,权限管理实现对⽤户访问系统的控制,按照安全规则或者安全策略控制⽤户可以访问⽽且只能访问⾃⼰被授权的资源。权限管理包括⽤户身份认证和授权两部分,简称认证授权。对于需要访问控制的资源⽤户⾸先经过身份认证,认证通过后⽤户具有该资源的访问权限⽅可访问。

认证

身份认证,就是判断⼀个⽤户是否为合法⽤户的处理过程。最常⽤的简单身份认证⽅式是系统通过核对⽤户输⼊的⽤户名和⼝令,看其是否与系统中存储的该⽤户的⽤户名和⼝令⼀致,来判断⽤户身份是否正确。对于采⽤指纹等系统,则出示指纹;对于硬件Key等刷卡系统,则需要刷卡。

授权

授权,即访问控制,控制谁能访问哪些资源。主体进⾏身份认证后需要分配权限⽅可访问系统的资源,对于某些资源没有权限是⽆法访问的

解决⽅案

和其他领域不同,在 Java 企业级开发中,安全管理框架⾮常少,⽬前⽐较常⻅的就是:

ShiroShiro 本身是⼀个⽼牌的安全管理框架,有着众多的优点,例如轻量、简单、易于集成、可以在JavaSE环境中使⽤等。不过,在微服务时代,Shiro 就显得⼒不从⼼了,在微服务⾯前和扩展⽅⾯,⽆法充分展示⾃⼰的优势。开发者⾃定义也有很多公司选择⾃定义权限,即⾃⼰开发权限管理。但是⼀个系统的安全,不仅仅是登录和权限控制这么简单,我们还要考虑种各样可能存在的⽹络政击以及防彻策略,从这个⻆度来说,开发者⽩⼰实现安全管理也并⾮是⼀件容易的事情,只有⼤公司才有⾜够的⼈⼒物⼒去⽀持这件事情。

Spring SecuritySpring Security,作为spring 家族的⼀员,在和 Spring 家族的其他成员如 Spring Boot Spring Clond等进⾏整合时,具有其他框架⽆可⽐拟的优势,同时对 OAuth2 有着良好的⽀持,再加上Spring Cloud对 Spring Security的不断加持(如推出 Spring Cloud Security ),让 Spring Securiy 不知不觉中成为微服务项⽬的⾸选安全管理⽅案。

整体架构

在的架构设计中,认证和授权 是分开的,⽆论使⽤什么样的认证⽅式。都不会影响授权,这是两个独⽴的存在,这种独⽴带来的好处之⼀,就是可以⾮常⽅便地整合⼀些外部的解决⽅案

SpringSecurity笔记【b站编程不良人】_第1张图片

认证

AuthenticationManager

在Spring Security中认证是由AuthenticationManager接⼝来负责的,接⼝定义为:

SpringSecurity笔记【b站编程不良人】_第2张图片

AuthenticationManager 主要实现类为 ProviderManager,在 ProviderManager

中管理了众多 AuthenticationProvider 实例。在⼀次完整的认证流程中,Spring Security 允许存在多个 AuthenticationProvider ,⽤来实现多种认证⽅式,这些 AuthenticationProvider 都是由 ProviderManager 进⾏统⼀管理的。

SpringSecurity笔记【b站编程不良人】_第3张图片

Authentication 

SpringSecurity笔记【b站编程不良人】_第4张图片

getAuthorities 获取⽤户权限信息

getCredentials 获取⽤户凭证信息,⼀般指密码

getDetails 获取⽤户详细信息

getPrincipal 获取⽤户身份信息,⽤户名、⽤户对象等

isAuthenticated ⽤户是否认证成功

SecurityContextHolder

SecurityContextHolder ⽤来获取登录之后⽤户信息。Spring Security 会将登录⽤户数据保存在 Session 中。但是,为了使⽤⽅便,Spring Security在此基础上还做了⼀些改进,其中最主要的⼀个变化就是线程绑定。当⽤户登录成功后,Spring Security 会将登录成功的⽤户信息保存到 SecurityContextHolder 中。

SecurityContextHolder 中的数据保存默认是通过ThreadLocal 来实现的,使⽤ ThreadLocal 创建的变量只能被当前线程访问,不能被其他线程访问和修改,也就是⽤户数据和请求线程绑定在⼀起。当登录请求处理完毕后,Spring Security 会将 SecurityContextHolder 中的数据拿出来保存到 Session 中,同时将 SecurityContexHolder 中的数据清空。以后每当有请求到来时,Spring Security就会先从 Session 中取出⽤户登录数据,保存到 SecurityContextHolder 中,⽅便在该请求的后续处理过程中使⽤,同时在请求结束时将 SecurityContextHolder 中的数据拿出来保存到 Session 中,然后将 Security SecurityContextHolder 中的数据清空。这⼀策略⾮常⽅便⽤户在 Controller、Service 层以及任何代码中获取当前登录⽤户数据。

springboot整合springsecurity

环境搭建 

引入依赖

        
        
            org.springframework.boot
            spring-boot-starter-security
        

只需引入这个依赖,所有的接⼝就会⾃动保护起来!

springsecurity提供默认的登录页面

SpringSecurity笔记【b站编程不良人】_第5张图片

实现原理:

https:"docs.spring.io/spring-security/site/docs/5.5.4/reference/html

5/#servlet-architecture

 

虽然开发者只需要引⼊⼀个依赖,就可以让  Spring Security 对应⽤进⾏保护。  Spring Security 是如何做到的呢?

在  Spring Security   认证、授权  等功能都是基于过滤器完成的

SpringSecurity笔记【b站编程不良人】_第6张图片

需要注的是,默认过滤器并不是直接放在  Web 项⽬的原⽣过滤器链中,⽽是通过⼀geFlterChainProxy 来统⼀管理。  Spring Security 中的过滤器链通过FilterChainProxy 嵌⼊到  Web项⽬的原⽣过滤器链中。  FilterChainProxy  作为 个顶层的管理者,将统⼀管理Security FilterFilterChainProxy 本身是通过Spring 框架提供的  DelegatingFilterProxy 整合到原⽣的过滤器链

Security Filters

那么在  Spring Security 中给我们提供那些过滤器 ? 默认情况下那些过滤器会被加载

呢?

过滤

过滤器作⽤

默认是否

加载

ChannelProcessingFilter

请求协议  HTTP HTTPS

NO

WebAsyncManagerIntegrationFilter

  WebAsyncManger 与  SpringSecurity 上下⽂进 ⾏集成

YES

SecurityContextPersistenceFilter

在处理请求之前 ,安全信息加载到

SecurityContextHolder 

YES

HeaderWriterFilter

头信息加⼊响应中

YES

CorsFilter

跨域问题

NO

CsrfFilter

处理  CSRF 

YES

LogoutFilter

注销登录

YES

OAuth2AuthorizationRequestRedirectFilter

处理  OAuth2 认证重定向

NO

Saml2WebSsoAuthenticationRequestFilter

处理  SAML 

NO

X509AuthenticationFilter

处理  X509

NO

AbstractPreAuthenticatedProcessingFilter

处理预认证问题

NO

CasAuthenticationFilter

理  CAS 单点登录

NO

OAuth2LoginAuthenticationFilter

处理  OAuth2 认证

NO

Saml2WebSsoAuthenticationFilter

处理  SAML 

NO

UsernamePasswordAuthenticationFilter

表单登录

YES

OpenIDAuthenticationFilter

理  OpenID 认证

NO

DefaultLoginPageGeneratingFilter

配置默认登录⻚⾯

YES

DefaultLogoutPageGeneratingFilter

配置默认注销⻚⾯

YES

ConcurrentSessionFilter

  Session 有效期

NO

DigestAuthenticationFilter

  HTTP 摘要认证

NO

BearerTokenAuthenticationFilter

理  OAuth2 认证的  Access Token

NO

BasicAuthenticationFilter

  HttpBasic 登录

YES

RequestCacheAwareFilter

请求缓存

YES

SecurityContextHolder<br

'AwareRequestFilter

装原始请求

YES

JaasApiIntegrationFilter

处理  JAAS 

NO

RememberMeAuthenticationFilter

处理  RememberMe 

NO

AnonymousAuthenticationFilter

匿名认证

YES

OAuth2AuthorizationCodeGrantFilter

OAuth2认证中授权码

NO

SessionManagementFilter

处理  session 并发问

YES

ExceptionTranslationFilter

理认证/授权中的异常

YES

FilterSecurityInterceptor

授权相关

YES

SwitchUserFilter

账户切换

NO

可以看出, Spring Security 提供了  30 多个过滤器。默认情况下Spring Boot 在对 Spring Security 进⼊⾃动化配置时,会创建⼀个名为  SpringSecurityFilerChain 的过滤器,并注⼊到  Spring 容器中,这个过滤器将负责所有的安全管理,包括⽤户认证、 授权、重定向到登录⻚⾯等。具体可以参考WebSecurityConfiguration的源码 :

SpringSecurity笔记【b站编程不良人】_第7张图片

SpringSecurity笔记【b站编程不良人】_第8张图片

 SpringBootWebSecurityConfiguration

这个类是  spring boot ⾃动配置类,通过这个源码得知,默认情况下对所有请求进⾏权控制 :

@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity
http)
throws Exception {
http.authorizeRequests().anyRequest()
.authenticated().and().formLogin().and().httpBasic();
return http.build();
}
}

SpringSecurity笔记【b站编程不良人】_第9张图片 这就是为什么在引⼊  Spring Security 中没有任何配置情况下,请求会被拦截的原因!

条件⼀  classpath中存在  SecurityFilterChain.class,HttpSecurity.class

条件⼆  没有⾃定义  WebSecurityConfigurerAdapter.class,SecurityFilterChain.class

class DefaultWebSecurityCondition extends AllNestedConditions {

DefaultWebSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}

@ConditionalOnClass({ SecurityFilterChain.class,
HttpSecurity.class })
static class Classes {

}

@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class,
SecurityFilterChain.class })

static class Beans {

}

}

 情况下,条件都是满⾜的。  WebSecurityConfigurerAdapter 这个类极其重要, Spring Security 核⼼配置都在这个类中 :

SpringSecurity笔记【b站编程不良人】_第10张图片

 如果要对  Spring Security 进⾏⾃定义配置,就要⾃定义这个类实例,通过覆盖类中⽅ 法达到修改默认配置的⽬的。

程分析

SpringSecurity笔记【b站编程不良人】_第11张图片

1. 请求  /hello 接⼝,在引⼊  spring security 之后会先经过⼀些列过滤器

2. 在请求到达  FilterSecurityInterceptor时,发现请求并未认证。请求拦截下来, 并抛出  AccessDeniedException 异常。

3. 抛出  AccessDeniedException 的异常会被  ExceptionTranslationFilter  获,这个  Filter 中会调⽤  LoginUrlAuthenticationEntryPoint#commence ⽅法给客户端返回  302,要求客户端进⾏重定向到  /login ⻚⾯。

4. 客户端发送  /login 请求。

5. /login 请求会再次被拦截器中  DefaultLoginPageGeneratingFilter 拦截到, 并在拦截器中返回⽣成登录⻚⾯

就是通过这种⽅式,  Spring Security 默认过滤器中⽣成了登录⻚⾯,并返回!

认⽤户⽣成

1. 查看  SpringBootWebSecurityConfiguration#defaultSecurityFilterChain 法表单登录

SpringSecurity笔记【b站编程不良人】_第12张图片

 2. 处理登录为  FormLoginConfigurer 类中  调UsernamePasswordAuthenticationFilter这个类实例

SpringSecurity笔记【b站编程不良人】_第13张图片

3. 查看类中  UsernamePasswordAuthenticationFilter的attempAuthentication ⽅法得实际调⽤  AuthenticationManager 中  authenticate ⽅法 

SpringSecurity笔记【b站编程不良人】_第14张图片

 4. 调⽤  ProviderManager 类中⽅法  authenticate

SpringSecurity笔记【b站编程不良人】_第15张图片

5. 调⽤了  ProviderManager 实现类中AbstractUserDetailsAuthenticationProvider类中⽅法

 SpringSecurity笔记【b站编程不良人】_第16张图片

6. 最终调⽤实现类  DaoAuthenticationProvider 类中⽅法⽐ 

SpringSecurity笔记【b站编程不良人】_第17张图片

 看到这⾥就知道默认实现是基于 InMemoryUserDetailsManager 这个类 ,也就是内存的  !

UserDetailService

通过上面源码分析也能得知  UserDetailService 是顶层⽗接⼝,接⼝loadUserByUserName ⽅法是⽤来在认证时进⾏⽤户名认证⽅法,默认实现使⽤是内存实 现,果想要修改数据库实现我们只需要⾃定义  UserDetailService 实现,最终返回   UserDetails 实例即可

public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException;
}

SpringSecurity笔记【b站编程不良人】_第18张图片

 UserDetailServiceAutoConfigutation

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean(
value = { AuthenticationManager.class,
AuthenticationProvider.class, UserDetailsService.class,
AuthenticationManagerResolver.class },
type = { "org.springframework.security.oauth2.jwt.JwtDecoder",

"org.springframework.security.oauth2.server.resource.introspection
.OpaqueTokenIntrospector",

"org.springframework.security.oauth2.client.registration.ClientReg
istrationRepository" })
public class UserDetailsServiceAutoConfiguration {
"....
@Bean
@Lazy
public InMemoryUserDetailsManager
inMemoryUserDetailsManager(SecurityProperties properties,
ObjectProvider passwordEncoder) {
SecurityProperties.User user = properties.getUser();
List roles = user.getRoles();
return new InMemoryUserDetailsManager(

User.withUsername(user.getName()).password(getOrDeducePassword(use
r, passwordEncoder.getIfAvailable()))

.roles(StringUtils.toStringArray(roles)).build());
}
}

1. 从⾃动配置源码中得知当  classpath 下存在  AuthenticationManager 

2. 当前项⽬中,系统没有提供  AuthenticationManager.classAuthenticationProvider.classUserDetailsService.classAuthenticationManagerResolver.class

认情况下都会满⾜,此时Spring Security会提供⼀个InMemoryUserDetailManager 实例

SpringSecurity笔记【b站编程不良人】_第19张图片

@ConfigurationProperties(prefix = "spring.security")
public class SecurityProperties {
private final User user = new User();
public User getUser() {
return this.user;
}
"....
public static class User {
private String name = "user";
private String password = UUID.randomUUID().toString();
private List roles = new ArrayList)();
private boolean passwordGenerated = true;
"get set (
}
}

 

这就是默认⽣成  user 以及  uuid 密码过程! 另外看明⽩源码之后,就知道只要在配置⽂

件中加⼊如下配置可以对内存中⽤户和密码进⾏覆盖。

spring.security.user.name=root
spring.security.user.password=root
spring.security.user.roles=admin,users

总结

 AuthenticationManagerProviderManger、以及  AuthenticationProvider三者关系

SpringSecurity笔记【b站编程不良人】_第20张图片

WebSecurityConfigurerAdapter 扩展  Spring Security 所有默认配置 

 SpringSecurity笔记【b站编程不良人】_第21张图片

  UserDetailService ⽤来修改默认认证的数据源信息

SpringSecurity笔记【b站编程不良人】_第22张图片

 

你可能感兴趣的:(系统安全,安全,spring,boot)