Update SpringSecurity流程补充.md

pull/142/head
Yang Libin 2 years ago committed by GitHub
parent ec936747c3
commit 017c3b3e84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,27 +1,26 @@
# springSecurity 流程补充 # SpringSecurity 流程补充
注意: 注意:
1. 基于 spring-boot-dependencies:2.7.7 1. 基于 spring-boot-dependencies:2.7.7
2. 首先需要了解[springboot2.7 升级](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes) 2. 首先需要了解 [springboot2.7 升级](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes)
`Changes to Auto-configuration` 以后使用`autoconfigure`进行自动注入 `Changes to Auto-configuration` 以后使用 `autoconfigure` 进行自动注入
3. 3. 代码地址 [io.github.poo0054](https://github.com/poo0054/security-study/blob/master/starter/src/main/java/io/github/poo0054/security/StarterApplication.java)
代码地址[io.github.poo0054](https://github.com/poo0054/security-study/blob/master/starter/src/main/java/io/github/poo0054/security/StarterApplication.java)
## 启动 ## 启动
我们每次添加` <artifactId>spring-boot-starter-security</artifactId>` 我们每次添加 `<artifactId>spring-boot-starter-security</artifactId>`,启动的时候会有一条类似的日志:
,启动的时候启动日志会有一条类似
`Using generated springSecurity password: 1db8eb87-e2ee-4c72-88e7-9b85268c4430 ```
Using generated springSecurity password: 1db8eb87-e2ee-4c72-88e7-9b85268c4430
This generated password is for development use only. Your springSecurity configuration must be updated before running your This generated password is for development use only. Your springSecurity configuration must be updated before running your
application in production.` application in production.
```
的日志。找到`UserDetailsServiceAutoConfiguration#InMemoryUserDetailsManager`类,它是 springboot 自动装配的。 找到 `UserDetailsServiceAutoConfiguration#InMemoryUserDetailsManager` 类,它是 springboot 自动装配的。
下面这些都是 springboot 自动装配类,在`spring-boot-autoconfigure-2.7.7.jar`>META-INF>spring> 下面这些都是 springboot 自动装配类,在 `spring-boot-autoconfigure-2.7.7.jar` > META-INF > spring > org.springframework.boot.autoconfigure.AutoConfiguration.imports 中。这些类就是 Spring Security 的全部了。
org.springframework.boot.autoconfigure.AutoConfiguration.imports 中. 这些类就是 springSecurity 的全部了.
```imports ```imports
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
@ -70,8 +69,6 @@ public class SecurityAutoConfiguration {
这个是 springSecurity 的核心配置类`SecurityProperties`,里面能配置 这个是 springSecurity 的核心配置类`SecurityProperties`,里面能配置
`filter`: 过滤,`user` : 用户信息 `filter`: 过滤,`user` : 用户信息
`这个有个问题filter是属于tomcat的springSecurity 中使用什么方式让filter变的有序的`
### @Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class }) ### @Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class })
这里导入了 2 个类 `SpringBootWebSecurityConfiguration`和`SecurityDataConfiguration``SecurityDataConfiguration`是 Spring 这里导入了 2 个类 `SpringBootWebSecurityConfiguration`和`SecurityDataConfiguration``SecurityDataConfiguration`是 Spring
@ -79,7 +76,7 @@ springSecurity 与 Spring 数据的集成,暂时不做讲解,重点是`Sprin
#### SpringBootWebSecurityConfiguration #### SpringBootWebSecurityConfiguration
这个类就是一个`Configuration`类,条件必须为`@ConditionalOnWebApplication(type = Type.SERVLET)`才会注入 这个类就是一个 `Configuration` 类,条件必须为 `@ConditionalOnWebApplication(type = Type.SERVLET)` 才会注入
##### SecurityFilterChainConfiguration ##### SecurityFilterChainConfiguration
@ -193,6 +190,7 @@ UserDetailsManager 的非持久化实现,支持内存映射。
## SecurityFilterAutoConfiguration ## SecurityFilterAutoConfiguration
SpringSecurity 的过滤器 SpringSecurity 的过滤器
自动配置。与 SpringBootWebSecurityConfiguration 分开配置,以确保在存在用户提供的 WebSecurityConfiguration 时,过滤器的顺序仍然被配置。 自动配置。与 SpringBootWebSecurityConfiguration 分开配置,以确保在存在用户提供的 WebSecurityConfiguration 时,过滤器的顺序仍然被配置。
### DelegatingFilterProxyRegistrationBean ### DelegatingFilterProxyRegistrationBean
@ -329,28 +327,28 @@ public @interface EnableWebSecurity {
然后在`SecurityBuilder`的实现类`AbstractConfiguredSecurityBuilder`的`doBuild()`方法进行很多别的操作。 然后在`SecurityBuilder`的实现类`AbstractConfiguredSecurityBuilder`的`doBuild()`方法进行很多别的操作。
```java ```java
protected final O doBuild()throws Exception{ protected final O doBuild() throws Exception {
synchronized (this.configurers){ synchronized (this.configurers) {
this.buildState=BuildState.INITIALIZING; this.buildState = BuildState.INITIALIZING;
beforeInit(); beforeInit();
init(); init();
this.buildState=BuildState.CONFIGURING; this.buildState = BuildState.CONFIGURING;
beforeConfigure(); beforeConfigure();
configure(); configure();
this.buildState=BuildState.BUILDING; this.buildState = BuildState.BUILDING;
O result=performBuild(); O result = performBuild();
this.buildState=BuildState.BUILT; this.buildState = BuildState.BUILT;
return result; return result;
} }
} }
``` ```
回到原来地方,返回的`webSecurityConfigurers`,里面的 回到原来地方,返回的`webSecurityConfigurers`,里面的
```java ```java
for(SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer:webSecurityConfigurers){ for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
this.webSecurity.apply(webSecurityConfigurer); this.webSecurity.apply(webSecurityConfigurer);
} }
``` ```
然后就到了`AbstractConfiguredSecurityBuilder#apply`方法,里面调用了`add(configurer);` 也就是把`SecurityConfigurer` 然后就到了`AbstractConfiguredSecurityBuilder#apply`方法,里面调用了`add(configurer);` 也就是把`SecurityConfigurer`
@ -372,19 +370,19 @@ for(SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer:webSecurityCon
这个里面最关键的也就是这个了。 这个里面最关键的也就是这个了。
```java ```java
for(SecurityFilterChain securityFilterChain:this.securityFilterChains){ for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(()->securityFilterChain); this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for(Filter filter:securityFilterChain.getFilters()){ for (Filter filter : securityFilterChain.getFilters()) {
if(filter instanceof FilterSecurityInterceptor){ if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor)filter); this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break; break;
} }
} }
} }
for(WebSecurityCustomizer customizer:this.webSecurityCustomizers){ for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity); customizer.customize(this.webSecurity);
} }
return this.webSecurity.build(); return this.webSecurity.build();
``` ```
首先使用根据获取到的`securityFilterChains`set 入`WebSecurity#securityFilterChainBuilders`的 List 属性 首先使用根据获取到的`securityFilterChains`set 入`WebSecurity#securityFilterChainBuilders`的 List 属性
@ -419,10 +417,10 @@ static class SecurityFilterChainConfiguration {
继续回到上面, 继续回到上面,
```java ```java
if(filter instanceof FilterSecurityInterceptor){ if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor)filter); this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break; break;
} }
``` ```
`FilterSecurityInterceptor`也在这里进行处理,也就是`SecurityMetadataSource`元数据 `FilterSecurityInterceptor`也在这里进行处理,也就是`SecurityMetadataSource`元数据
@ -430,28 +428,28 @@ if(filter instanceof FilterSecurityInterceptor){
然后自定义的`WebSecurityCustomizer`也在这里。可以自行改变`webSecurity` 然后自定义的`WebSecurityCustomizer`也在这里。可以自行改变`webSecurity`
```java ```java
for(WebSecurityCustomizer customizer:this.webSecurityCustomizers){ for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity); customizer.customize(this.webSecurity);
} }
``` ```
接下来就是构建了,来到`AbstractConfiguredSecurityBuilder#doBuild()` 接下来就是构建了,来到 `AbstractConfiguredSecurityBuilder#doBuild()`
```java ```java
protected final O doBuild()throws Exception{ protected final O doBuild() throws Exception {
synchronized (this.configurers){ synchronized (this.configurers) {
this.buildState=BuildState.INITIALIZING; this.buildState = BuildState.INITIALIZING;
beforeInit(); beforeInit();
init(); init();
this.buildState=BuildState.CONFIGURING; this.buildState = BuildState.CONFIGURING;
beforeConfigure(); beforeConfigure();
configure(); configure();
this.buildState=BuildState.BUILDING; this.buildState = BuildState.BUILDING;
O result=performBuild(); O result = performBuild();
this.buildState=BuildState.BUILT; this.buildState = BuildState.BUILT;
return result; return result;
} }
} }
``` ```
> init(); > init();
@ -502,25 +500,25 @@ synchronized (this.configurers){
其实到了这一步。后面的就是我们自己编写的代码了比如 其实到了这一步。后面的就是我们自己编写的代码了比如
```java ```java
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exception{ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 配置认证 // 配置认证
http.formLogin(); http.formLogin();
// 设置URL的授权问题 // 设置URL的授权问题
// 多个条件取交集 // 多个条件取交集
http.authorizeRequests() http.authorizeRequests()
// 匹配 / 控制器 permitAll() 不需要被认证就可以访问 // 匹配 / 控制器 permitAll() 不需要被认证就可以访问
.antMatchers("/login").permitAll() .antMatchers("/login").permitAll()
.antMatchers("/error").permitAll() .antMatchers("/error").permitAll()
.antMatchers("/fail").permitAll() .antMatchers("/fail").permitAll()
// anyRequest() 所有请求 authenticated() 必须被认证 // anyRequest() 所有请求 authenticated() 必须被认证
.anyRequest().authenticated(); .anyRequest().authenticated();
// .accessDecisionManager(accessDecisionManager()); // .accessDecisionManager(accessDecisionManager());
// 关闭csrf // 关闭csrf
http.csrf().disable(); http.csrf().disable();
return http.build(); return http.build();
} }
``` ```
或者继承 WebSecurityConfigurerAdapter 的类了。 或者继承 WebSecurityConfigurerAdapter 的类了。
@ -530,12 +528,12 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exceptio
```java ```java
@Bean @Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER) @Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)throws Exception{ SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated(); http.authorizeRequests().anyRequest().authenticated();
http.formLogin(); http.formLogin();
http.httpBasic(); http.httpBasic();
return http.build(); return http.build();
} }
``` ```
首先获取`HttpSecurity http`(这里的`HttpSecurity`是从`HttpSecurityConfiguration` 首先获取`HttpSecurity http`(这里的`HttpSecurity`是从`HttpSecurityConfiguration`
@ -558,27 +556,27 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exceptio
这个有一个很有意思的类`FilterOrderRegistration`。 前面问的根据 filter 是如何包装顺序的。就在这个类里面 这个有一个很有意思的类`FilterOrderRegistration`。 前面问的根据 filter 是如何包装顺序的。就在这个类里面
```java ```java
FilterOrderRegistration(){ FilterOrderRegistration() {
Step order=new Step(INITIAL_ORDER,ORDER_STEP); Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class,order.next()); put(DisableEncodeUrlFilter.class, order.next());
put(ForceEagerSessionCreationFilter.class,order.next()); put(ForceEagerSessionCreationFilter.class, order.next());
put(ChannelProcessingFilter.class,order.next()); put(ChannelProcessingFilter.class, order.next());
order.next(); // gh-8105 order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class,order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextHolderFilter.class,order.next()); put(SecurityContextHolderFilter.class, order.next());
put(SecurityContextPersistenceFilter.class,order.next()); put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class,order.next()); put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class,order.next()); put(CorsFilter.class, order.next());
put(CsrfFilter.class,order.next()); put(CsrfFilter.class, order.next());
put(LogoutFilter.class,order.next()); put(LogoutFilter.class, order.next());
// ..... }
``` ```
springSecurity 事先使用这个类把预加载的类全部排序好,然后每次 add 一个新的 filter 就会使用这个里面的序号。如果我们有自定义的类,也要提前加载到里面去,不然就会 springSecurity 事先使用这个类把预加载的类全部排序好,然后每次 add 一个新的 filter 就会使用这个里面的序号。如果我们有自定义的类,也要提前加载到里面去,不然就会
```java ```java
throw new IllegalArgumentException("The Filter class "+filter.getClass().getName() throw new IllegalArgumentException("The Filter class "+filter.getClass().getName()
+" does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."); +" does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
``` ```
`WebAsyncManagerIntegrationFilter`: 与处理异步 web 请求相关的实用程序方法 `WebAsyncManagerIntegrationFilter`: 与处理异步 web 请求相关的实用程序方法
@ -678,16 +676,16 @@ public interface SecurityFilterChain {
```java ```java
@Bean @Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
ApplicationContext context){ ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder=new LazyPasswordEncoder(context); LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
AuthenticationEventPublisher authenticationEventPublisher=getAuthenticationEventPublisher(context); AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
DefaultPasswordEncoderAuthenticationManagerBuilder result=new DefaultPasswordEncoderAuthenticationManagerBuilder( DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
objectPostProcessor,defaultPasswordEncoder); objectPostProcessor, defaultPasswordEncoder);
if(authenticationEventPublisher!=null){ if (authenticationEventPublisher != null) {
result.authenticationEventPublisher(authenticationEventPublisher); result.authenticationEventPublisher(authenticationEventPublisher);
} }
return result; return result;
} }
``` ```
这里面返回了一个`AuthenticationManagerBuilder`的 bean也就是上面`` 这里面返回了一个`AuthenticationManagerBuilder`的 bean也就是上面``
@ -707,24 +705,24 @@ HttpSecurityConfiguration#httpSecurity()`的时候需要的类,这个类也是
就是`AuthenticationManagerBuilder`的真正实现了。接下来回到`getAuthenticationManager()`方法 就是`AuthenticationManagerBuilder`的真正实现了。接下来回到`getAuthenticationManager()`方法
```java ```java
public AuthenticationManager getAuthenticationManager()throws Exception{ public AuthenticationManager getAuthenticationManager() throws Exception {
if(this.authenticationManagerInitialized){ if (this.authenticationManagerInitialized) {
return this.authenticationManager; return this.authenticationManager;
} }
AuthenticationManagerBuilder authBuilder=this.applicationContext.getBean(AuthenticationManagerBuilder.class); AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
if(this.buildingAuthenticationManager.getAndSet(true)){ if (this.buildingAuthenticationManager.getAndSet(true)) {
return new AuthenticationManagerDelegator(authBuilder); return new AuthenticationManagerDelegator(authBuilder);
} }
for(GlobalAuthenticationConfigurerAdapter config:this.globalAuthConfigurers){ for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
authBuilder.apply(config); authBuilder.apply(config);
} }
this.authenticationManager=authBuilder.build(); this.authenticationManager = authBuilder.build();
if(this.authenticationManager==null){ if (this.authenticationManager == null) {
this.authenticationManager=getAuthenticationManagerBean(); this.authenticationManager = getAuthenticationManagerBean();
} }
this.authenticationManagerInitialized=true; this.authenticationManagerInitialized = true;
return this.authenticationManager; return this.authenticationManager;
} }
``` ```
> AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class); > AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
@ -732,31 +730,31 @@ public AuthenticationManager getAuthenticationManager()throws Exception{
获取到`DefaultPasswordEncoderAuthenticationManagerBuilder` 获取到`DefaultPasswordEncoderAuthenticationManagerBuilder`
```java ```java
for(GlobalAuthenticationConfigurerAdapter config:this.globalAuthConfigurers){ for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
authBuilder.apply(config); authBuilder.apply(config);
} }
``` ```
需要注意的是,`this.globalAuthConfigurers`就是上面三个类, 需要注意的是,`this.globalAuthConfigurers`就是上面三个类,
```java ```java
@Bean @Bean
public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer( public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
ApplicationContext context){ ApplicationContext context) {
return new EnableGlobalAuthenticationAutowiredConfigurer(context); return new EnableGlobalAuthenticationAutowiredConfigurer(context);
} }
@Bean @Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer( public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(
ApplicationContext context){ ApplicationContext context) {
return new InitializeUserDetailsBeanManagerConfigurer(context); return new InitializeUserDetailsBeanManagerConfigurer(context);
} }
@Bean @Bean
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer( public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(
ApplicationContext context){ ApplicationContext context) {
return new InitializeAuthenticationProviderBeanManagerConfigurer(context); return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
} }
``` ```
调用了`apply`也就是`add`方法。添加到`configurers`中 调用了`apply`也就是`add`方法。添加到`configurers`中
@ -790,28 +788,28 @@ public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAu
2: `InitializeUserDetailsManagerConfigurer#configure`方法 2: `InitializeUserDetailsManagerConfigurer#configure`方法
```java ```java
@Override @Override
public void configure(AuthenticationManagerBuilder auth)throws Exception{ public void configure(AuthenticationManagerBuilder auth) throws Exception {
if(auth.isConfigured()){ if (auth.isConfigured()) {
return; return;
} }
UserDetailsService userDetailsService=getBeanOrNull(UserDetailsService.class); UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
if(userDetailsService==null){ if (userDetailsService == null) {
return; return;
} }
PasswordEncoder passwordEncoder=getBeanOrNull(PasswordEncoder.class); PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
UserDetailsPasswordService passwordManager=getBeanOrNull(UserDetailsPasswordService.class); UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
DaoAuthenticationProvider provider=new DaoAuthenticationProvider(); DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService); provider.setUserDetailsService(userDetailsService);
if(passwordEncoder!=null){ if (passwordEncoder != null) {
provider.setPasswordEncoder(passwordEncoder); provider.setPasswordEncoder(passwordEncoder);
} }
if(passwordManager!=null){ if (passwordManager != null) {
provider.setUserDetailsPasswordService(passwordManager); provider.setUserDetailsPasswordService(passwordManager);
} }
provider.afterPropertiesSet(); provider.afterPropertiesSet();
auth.authenticationProvider(provider); auth.authenticationProvider(provider);
} }
``` ```
获取所有`UserDetailsService`和`PasswordEncoder`和`UserDetailsPasswordService`,使用`DaoAuthenticationProvider` 获取所有`UserDetailsService`和`PasswordEncoder`和`UserDetailsPasswordService`,使用`DaoAuthenticationProvider`
@ -823,16 +821,16 @@ public void configure(AuthenticationManagerBuilder auth)throws Exception{
然后又到了熟悉的`AuthenticationManagerBuilder#performBuild` 然后又到了熟悉的`AuthenticationManagerBuilder#performBuild`
```java ```java
ProviderManager providerManager=new ProviderManager(this.authenticationProviders, ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
this.parentAuthenticationManager); this.parentAuthenticationManager);
if(this.eraseCredentials!=null){ if (this.eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials); providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
} }
if(this.eventPublisher!=null){ if (this.eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(this.eventPublisher); providerManager.setAuthenticationEventPublisher(this.eventPublisher);
} }
providerManager=postProcess(providerManager); providerManager = postProcess(providerManager);
return providerManager; return providerManager;
``` ```
首先使用`ProviderManager`管理`authenticationProviders`和`parentAuthenticationManager`,这里的`eraseCredentials` 首先使用`ProviderManager`管理`authenticationProviders`和`parentAuthenticationManager`,这里的`eraseCredentials`
@ -904,17 +902,16 @@ class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut i
```java ```java
@Override @Override
public Object invoke(MethodInvocation mi)throws Throwable{ public Object invoke(MethodInvocation mi) throws Throwable {
InterceptorStatusToken token=super.beforeInvocation(mi); InterceptorStatusToken token = super.beforeInvocation(mi);
Object result; Object result;
try{ try {
result=mi.proceed(); result = mi.proceed();
} } finally {
finally{
super.finallyInvocation(token); super.finallyInvocation(token);
} }
return super.afterInvocation(token,result); return super.afterInvocation(token, result);
} }
``` ```
这个一看就是标准 aop 这个一看就是标准 aop
@ -928,12 +925,12 @@ public Object invoke(MethodInvocation mi)throws Throwable{
接着来到了`DelegatingMethodSecurityMetadataSource#getAttributes` 接着来到了`DelegatingMethodSecurityMetadataSource#getAttributes`
```java ```java
for(MethodSecurityMetadataSource s:this.methodSecurityMetadataSources){ for (MethodSecurityMetadataSource s : this.methodSecurityMetadataSources) {
attributes=s.getAttributes(method,targetClass); attributes = s.getAttributes(method, targetClass);
if(attributes!=null&&!attributes.isEmpty()){ if (attributes != null && !attributes.isEmpty()) {
break; break;
} }
} }
``` ```
`this.methodSecurityMetadataSources`里面的值,就是`GlobalMethodSecurityConfiguration#methodSecurityMetadataSource` `this.methodSecurityMetadataSources`里面的值,就是`GlobalMethodSecurityConfiguration#methodSecurityMetadataSource`
@ -976,25 +973,25 @@ public Object invoke(MethodInvocation mi)throws Throwable{
这个就是`AbstractSecurityInterceptor#attemptAuthorization`的授权方法 这个就是`AbstractSecurityInterceptor#attemptAuthorization`的授权方法
```java ```java
protected AccessDecisionManager accessDecisionManager(){ protected AccessDecisionManager accessDecisionManager(){
List<AccessDecisionVoter<?>>decisionVoters=new ArrayList<>(); List<AccessDecisionVoter<?>>decisionVoters=new ArrayList<>();
if(prePostEnabled()){ if(prePostEnabled()){
ExpressionBasedPreInvocationAdvice expressionAdvice=new ExpressionBasedPreInvocationAdvice(); ExpressionBasedPreInvocationAdvice expressionAdvice=new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler()); expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
} }
if(jsr250Enabled()){ if(jsr250Enabled()){
decisionVoters.add(new Jsr250Voter()); decisionVoters.add(new Jsr250Voter());
} }
RoleVoter roleVoter=new RoleVoter(); RoleVoter roleVoter=new RoleVoter();
GrantedAuthorityDefaults grantedAuthorityDefaults=getSingleBeanOrNull(GrantedAuthorityDefaults.class); GrantedAuthorityDefaults grantedAuthorityDefaults=getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if(grantedAuthorityDefaults!=null){ if(grantedAuthorityDefaults!=null){
roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix()); roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
} }
decisionVoters.add(roleVoter); decisionVoters.add(roleVoter);
decisionVoters.add(new AuthenticatedVoter()); decisionVoters.add(new AuthenticatedVoter());
return new AffirmativeBased(decisionVoters); return new AffirmativeBased(decisionVoters);
} }
``` ```
前提条件必须开启`prePostEnabled` 前提条件必须开启`prePostEnabled`
@ -1028,18 +1025,18 @@ public Object invoke(MethodInvocation mi)throws Throwable{
首先看看我们一开始创建`HttpSecurity`的时候添加了哪些类 `HttpSecurityConfiguration#httpSecurity()` 首先看看我们一开始创建`HttpSecurity`的时候添加了哪些类 `HttpSecurityConfiguration#httpSecurity()`
```java ```java
@Bean(HTTPSECURITY_BEAN_NAME) @Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype") @Scope("prototype")
HttpSecurity httpSecurity()throws Exception{ HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder=new WebSecurityConfigurerAdapter.LazyPasswordEncoder( WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context); this.context);
AuthenticationManagerBuilder authenticationBuilder=new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder( AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor,passwordEncoder); this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager()); authenticationBuilder.parentAuthenticationManager(authenticationManager());
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher()); authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
HttpSecurity http=new HttpSecurity(this.objectPostProcessor,authenticationBuilder,createSharedObjects()); HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// @formatter:off // @formatter:off
http http
.csrf(withDefaults()) .csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter()) .addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults()) .exceptionHandling(withDefaults())
@ -1050,11 +1047,11 @@ public Object invoke(MethodInvocation mi)throws Throwable{
.anonymous(withDefaults()) .anonymous(withDefaults())
.servletApi(withDefaults()) .servletApi(withDefaults())
.apply(new DefaultLoginPageConfigurer<>()); .apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults()); http.logout(withDefaults());
// @formatter:on // @formatter:on
applyDefaultConfigurers(http); applyDefaultConfigurers(http);
return http; return http;
} }
``` ```
`CsrfConfigurer``ExceptionHandlingConfigurer``HeadersConfigurer``SessionManagementConfigurer``SecurityContextConfigurer``RequestCacheConfigurer``AnonymousConfigurer``ServletApiConfigurer``DefaultLoginPageConfigurer``LogoutConfigurer` `CsrfConfigurer``ExceptionHandlingConfigurer``HeadersConfigurer``SessionManagementConfigurer``SecurityContextConfigurer``RequestCacheConfigurer``AnonymousConfigurer``ServletApiConfigurer``DefaultLoginPageConfigurer``LogoutConfigurer`
@ -1077,41 +1074,42 @@ public Object invoke(MethodInvocation mi)throws Throwable{
首先创建对象给属性赋值 首先创建对象给属性赋值
```java ```java
authFilter=UsernamePasswordAuthenticationFilter() authFilter = UsernamePasswordAuthenticationFilter()
loginPage="/login" loginPage = "/login"
this.authenticationEntryPoint=new LoginUrlAuthenticationEntryPoint(loginPage); this.authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(loginPage);
``` ```
接着来到`init` 接着来到`init`
```java ```java
@Override @Override
public void init(B http)throws Exception{ public void init(B http) throws Exception {
updateAuthenticationDefaults(); updateAuthenticationDefaults();
updateAccessDefaults(http); updateAccessDefaults(http);
registerDefaultAuthenticationEntryPoint(http); registerDefaultAuthenticationEntryPoint(http);
} }
``` ```
> updateAuthenticationDefaults(); > updateAuthenticationDefaults();
```java ```java
/** /**
* Updates the default values for authentication. * Updates the default values for authentication.
*
* @throws Exception * @throws Exception
*/ */
protected final void updateAuthenticationDefaults(){ protected final void updateAuthenticationDefaults() {
if(this.loginProcessingUrl==null){ if (this.loginProcessingUrl == null) {
loginProcessingUrl(this.loginPage); loginProcessingUrl(this.loginPage);
} }
if(this.failureHandler==null){ if (this.failureHandler == null) {
failureUrl(this.loginPage+"?error"); failureUrl(this.loginPage + "?error");
} }
LogoutConfigurer<B> logoutConfigurer=getBuilder().getConfigurer(LogoutConfigurer.class); LogoutConfigurer<B> logoutConfigurer = getBuilder().getConfigurer(LogoutConfigurer.class);
if(logoutConfigurer!=null&&!logoutConfigurer.isCustomLogoutSuccess()){ if (logoutConfigurer != null && !logoutConfigurer.isCustomLogoutSuccess()) {
logoutConfigurer.logoutSuccessUrl(this.loginPage+"?logout"); logoutConfigurer.logoutSuccessUrl(this.loginPage + "?logout");
} }
} }
``` ```
`loginProcessingUrl(this.loginPage);` `loginProcessingUrl(this.loginPage);`
@ -1172,16 +1170,16 @@ private LinkedHashMap<RequestMatcher, AccessDeniedHandler> defaultDeniedHandlerM
过滤器,添加到了`http`中, 代码是这一段 过滤器,添加到了`http`中, 代码是这一段
```java ```java
@Override @Override
public void configure(H http){ public void configure(H http) {
AuthenticationEntryPoint entryPoint=getAuthenticationEntryPoint(http); AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
ExceptionTranslationFilter exceptionTranslationFilter=new ExceptionTranslationFilter(entryPoint, ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint,
getRequestCache(http)); getRequestCache(http));
AccessDeniedHandler deniedHandler=getAccessDeniedHandler(http); AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler); exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
exceptionTranslationFilter=postProcess(exceptionTranslationFilter); exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
http.addFilter(exceptionTranslationFilter); http.addFilter(exceptionTranslationFilter);
} }
``` ```
接着我们打开`ExceptionTranslationFilter`,这就是一个`Filter` 接着我们打开`ExceptionTranslationFilter`,这就是一个`Filter`
@ -1191,29 +1189,28 @@ public void configure(H http){
方法, 方法,
```java ```java
private void handleSpringSecurityException(HttpServletRequest request,HttpServletResponse response, private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain,RuntimeException exception)throws IOException,ServletException{ FilterChain chain, RuntimeException exception) throws IOException, ServletException {
if(exception instanceof AuthenticationException){ if (exception instanceof AuthenticationException) {
handleAuthenticationException(request,response,chain,(AuthenticationException)exception); handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
} } else if (exception instanceof AccessDeniedException) {
else if(exception instanceof AccessDeniedException){ handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
handleAccessDeniedException(request,response,chain,(AccessDeniedException)exception); }
} }
}
``` ```
发现最后还是到了 发现最后还是到了
```java ```java
protected void sendStartAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain, protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
AuthenticationException reason)throws ServletException,IOException{ AuthenticationException reason) throws ServletException, IOException {
// SEC-112: Clear the SecurityContextHolder's Authentication, as the // SEC-112: Clear the SecurityContextHolder's Authentication, as the
// existing Authentication is no longer considered valid // existing Authentication is no longer considered valid
SecurityContext context=SecurityContextHolder.createEmptyContext(); SecurityContext context = SecurityContextHolder.createEmptyContext();
SecurityContextHolder.setContext(context); SecurityContextHolder.setContext(context);
this.requestCache.saveRequest(request,response); this.requestCache.saveRequest(request, response);
this.authenticationEntryPoint.commence(request,response,reason); this.authenticationEntryPoint.commence(request, response, reason);
} }
``` ```
里面就有`this.authenticationEntryPoint.commence(request, response, reason);`这段代码, 里面就有`this.authenticationEntryPoint.commence(request, response, reason);`这段代码,
@ -1221,21 +1218,21 @@ public void configure(H http){
```java ```java
@Override @Override
public void commence(HttpServletRequest request,HttpServletResponse response, public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException)throws IOException,ServletException{ AuthenticationException authException) throws IOException, ServletException {
for(RequestMatcher requestMatcher:this.entryPoints.keySet()){ for (RequestMatcher requestMatcher : this.entryPoints.keySet()) {
logger.debug(LogMessage.format("Trying to match using %s",requestMatcher)); logger.debug(LogMessage.format("Trying to match using %s", requestMatcher));
if(requestMatcher.matches(request)){ if (requestMatcher.matches(request)) {
AuthenticationEntryPoint entryPoint=this.entryPoints.get(requestMatcher); AuthenticationEntryPoint entryPoint = this.entryPoints.get(requestMatcher);
logger.debug(LogMessage.format("Match found! Executing %s",entryPoint)); logger.debug(LogMessage.format("Match found! Executing %s", entryPoint));
entryPoint.commence(request,response,authException); entryPoint.commence(request, response, authException);
return; return;
}
}
logger.debug(LogMessage.format("No match found. Using default entry point %s",this.defaultEntryPoint));
// No EntryPoint matched, use defaultEntryPoint
this.defaultEntryPoint.commence(request,response,authException);
} }
}
logger.debug(LogMessage.format("No match found. Using default entry point %s", this.defaultEntryPoint));
// No EntryPoint matched, use defaultEntryPoint
this.defaultEntryPoint.commence(request, response, authException);
}
``` ```
基本上流程就完成了,请求先走过滤器,然后走不同的 filter报错就到了这一步进行错误处理其余都基本一致了 基本上流程就完成了,请求先走过滤器,然后走不同的 filter报错就到了这一步进行错误处理其余都基本一致了
@ -1275,11 +1272,11 @@ public @interface EnableWebSecurity {
使用方法 使用方法
```java ```java
@GetMapping("/get") @GetMapping("/get")
// public Users getUser(String username,@CsrfToken CsrfToken token, @AuthenticationPrincipal Users customUser, @CurrentSecurityContext Authentication authentication) { // public Users getUser(String username,@CsrfToken CsrfToken token, @AuthenticationPrincipal Users customUser, @CurrentSecurityContext Authentication authentication) {
public Users getUser(String username,@AuthenticationPrincipal Users customUser,@CurrentSecurityContext SecurityContext securityContext){ public Users getUser(String username, @AuthenticationPrincipal Users customUser, @CurrentSecurityContext SecurityContext securityContext) {
return userInfoService.getUsers(username); return userInfoService.getUsers(username);
} }
``` ```
里面的`SpringWebMvcImportSelector`类注入了`WebMvcSecurityConfiguration`,这就是 springmvc 中`HandlerMethodArgumentResolver` 里面的`SpringWebMvcImportSelector`类注入了`WebMvcSecurityConfiguration`,这就是 springmvc 中`HandlerMethodArgumentResolver`

Loading…
Cancel
Save