• spring-security-源码解析+自定义拓展


    1.参考文档

    https://docs.spring.io/spring-security/reference/5.7/servlet/architecture.html

    1.1.各种filterchain

    1.1.1.SecurityFilterChain

    在这里插入图片描述

    1.1.2.springSecurityFilterChain

    在这里插入图片描述

    1.1.3.Security Filters

    在这里插入图片描述

    2.几个重要的注解

    2.1.@EnableXXX

    1. @EnableWebMvcSecurity@deprecated
    2. @EnableWebSecurity
      • import: WebSecurityConfiguration
      • import: HttpSecurityConfiguration
      • import: SpringWebMvcImportSelector ===> WebMvcSecurityConfiguration(略)
      • import: OAuth2ImportSelector(略)
      • @EnableGlobalAuthentication(4)
    3. @EnableGlobalMethodSecurity
      • @EnableGlobalAuthentication(4)
      • import: GlobalMethodSecuritySelector ===> GlobalMethodSecurityConfiguration
    4. @EnableGlobalAuthentication
      • import: AuthenticationConfiguration

    2.2.AuthenticationConfiguration

    @Configuration(proxyBeanMethods = false)
    @Import(ObjectPostProcessorConfiguration.class)
    public class AuthenticationConfiguration {
    	private AuthenticationManager authenticationManager;
    	@Autowired(required = false)
    	private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections.emptyList();
    	
    	@Autowired
    	private ObjectPostProcessor<Object> objectPostProcessor;
    	
    	//1.
    	@Bean
    	public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
    			ApplicationContext context) {
    		LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
    		AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
    		//1.1
    		DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
    				objectPostProcessor, defaultPasswordEncoder);
    		if (authenticationEventPublisher != null) {
    			result.authenticationEventPublisher(authenticationEventPublisher);
    		}
    		return result;
    	}
    	
    	public AuthenticationManager getAuthenticationManager() throws Exception {
    		//2
    		AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class); //from 1
    		
    		//2.1 apply globalAuthConfigurers
    		for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
    			authBuilder.apply(config);
    		}
    		this.authenticationManager = authBuilder.build();
    		
    		this.authenticationManagerInitialized = true;
    		return this.authenticationManager;
    	}
    	
    	/**
    	@Bean EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter
    	@Bean InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter
    	@Bean InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter
    	**/
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2.2.1 ObjectPostProcessorConfiguration

    public class ObjectPostProcessorConfiguration {
    
    	@Bean
    	public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
    		return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.webSecurity 流程分析

    3.1.@EnableWebSecurity

    3.1.1.HttpSecurityConfiguration

    @Configuration(proxyBeanMethods = false)
    class HttpSecurityConfiguration {
    	@Autowired
    	private ObjectPostProcessor<Object> objectPostProcessor;
    	
    	@Autowired
    	private AuthenticationManager authenticationManager;
    	
    	@Autowired
    	private AuthenticationConfiguration authenticationConfiguration;
    	
    	@Bean(HTTPSECURITY_BEAN_NAME)
    	@Scope("prototype") //允许注入多个
    	HttpSecurity httpSecurity() throws Exception {
    		WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
    				this.context);
    		AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
    				this.objectPostProcessor, passwordEncoder);
    		authenticationBuilder.parentAuthenticationManager(authenticationManager());
    		authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
    		HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
    		// @formatter:off
    		http
    			.csrf(withDefaults())
    			.addFilter(new WebAsyncManagerIntegrationFilter())
    			.exceptionHandling(withDefaults())
    			.headers(withDefaults())
    			.sessionManagement(withDefaults())
    			.securityContext(withDefaults())
    			.requestCache(withDefaults())
    			.anonymous(withDefaults())
    			.servletApi(withDefaults())
    			.apply(new DefaultLoginPageConfigurer<>());
    		http.logout(withDefaults());
    		// @formatter:on
    		applyDefaultConfigurers(http); //1
    		return http;
    	}
    	
    	private void applyDefaultConfigurers(HttpSecurity http) throws Exception {
    		ClassLoader classLoader = this.context.getClassLoader();
    		List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
    				.loadFactories(AbstractHttpConfigurer.class, classLoader);
    		for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
    			http.apply(configurer);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.1.2.WebSecurityConfiguration

    public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    	private WebSecurity webSecurity;
    	
    	private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
    	
    	//securityFilterChains, 可有多个httpSecurity.buid()多个;
    	@Autowired(required = false)
    	private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
    	
    	@Autowired(required = false) 	
    	private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
    	
    	@Autowired(required = false)
    	private ObjectPostProcessor<Object> objectObjectPostProcessor;
    	
    	@Autowired(required = false)
    	public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
    			ConfigurableListableBeanFactory beanFactory) throws Exception {
    		//0.初始化 webSecurity
    		this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
    		
    		//AutowiredWebSecurityConfigurersIgnoreParents内部逻辑:this.beanFactory.getBeansOfType(WebSecurityConfigurer.class);
    		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
    				beanFactory).getWebSecurityConfigurers();
    		//webSecurityConfigurers 排序略.....
    		
    		//1.应用 webSecurityConfigurer;
    		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    			this.webSecurity.apply(webSecurityConfigurer);
    		}
    		this.webSecurityConfigurers = webSecurityConfigurers;
    	}
    	
    	//2. 注入 springSecurityFilterChain
    	@Bean(name = "springSecurityFilterChain"public Filter springSecurityFilterChain() throws Exception {
    		//2.1
    		WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
    					.postProcess(new WebSecurityConfigurerAdapter() {
    					});
    		this.webSecurity.apply(adapter);
    			
    		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
    			//2.2 "springSecurityFilterChain" 添加多个securityFilterChain
    			this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
    			
    			//2.3 添加FilterSecurityInterceptor
    			for (Filter filter : securityFilterChain.getFilters()) {
    				if (filter instanceof FilterSecurityInterceptor) {
    					this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
    					break;
    				}
    			}
    		}
    		
    		//2.4 应用webSecurityCustomizers
    		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
    			customizer.customize(this.webSecurity);
    		}
    		return this.webSecurity.build();
    	}
    	
    	//3. 注入privilegeEvaluator: 由webSecurity初始化生成
    	@Bean
    	public WebInvocationPrivilegeEvaluator privilegeEvaluator() {
    		return this.webSecurity.getPrivilegeEvaluator();
    	}
    	
    	//4. 注入webSecurityExpressionHandler: 由webSecurity初始化生成
    	@Bean
    	public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
    		return this.webSecurity.getExpressionHandler();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    3.2.总体处理流程(粗)

    request -> springSecurityFilterChain -> securityFilterChain[s]

    3.3.httpSecurity.build() 流程

    build

    @Bean // 可选,可配置多个
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .csrf().disable()
    	       		.addFilterBefore(xxxAuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class)
                    .authorizeRequests()
                    .expressionHandler(xxxWebExpressionHandler());
            registry
                    .antMatchers("/healthcheck/**").permitAll()
                    .antMatchers("/**")
                    .access("isLoggedIn()");
            return http.build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.3.1.httpSecurity类图

    在这里插入图片描述

    3.3.2.httpSecurity.build() 源码

    //总体流程
    httpSecurity.buid()
    	AbstractSecurityBuilder.build()
    		AbstractConfiguredSecurityBuilder.doBuild()
    			init(); // getConfigurers() --> Collection>
    			configure(); // for-each SecurityConfigurer.configure() --> 初始化Filter
    			beforeConfigure(); //由HttpSecurity重写: 初始化 authenticationManager
    			performBuild()
    				httpSecurity.performBuild()
    
    public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
    		implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
    
    	private final RequestMatcherConfigurer requestMatcherConfigurer;
    
    	//a.注入HttpSecurityConfiguration.httpSecurity()设置: 
    	private List<OrderedFilter> filters = new ArrayList<>();
    	private AuthenticationManager authenticationManager; //set
    
    	protected DefaultSecurityFilterChain performBuild() {
    		//a.注入HttpSecurityConfiguration.httpSecurity()设置: 
    
    		//b.用户 注册filterChain时 设置 ; 鉴权时会用到
    		ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
    		AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class); 
    		boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
    		
    		//sort 略....
    		List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
    		
    		return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
    	}
    
    
    }	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.3.webSecurity.build() 流程

    注入demo

       @Bean
        public WebSecurityCustomizer webSecurityCustomizer() {
            return (web) -> web.ignoring()
                    .antMatchers("/css/**")
                    .antMatchers("/html/**")
                    .antMatchers("/img/**")
                    .antMatchers("/js/**")
                    .antMatchers("/libs/**")
                    .antMatchers("/version.txt");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.3.1.WebSecurity类图(略)

    见HttpSecurity类图

    3.3.2.webSecurity.build() 源码

    //调用总体路径
    WebSecurity.build()
    		AbstractSecurityBuilder.build()
    			AbstractConfiguredSecurityBuilder.doBuild()
    				init(); // getConfigurers() --> Collection>
    				configure(); // for-each SecurityConfigurer.configure() --> 初始化Filter	
    				performBuild();
    					WebSecurity.performBuild() //1
    
    public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
    		implements SecurityBuilder<Filter>, ApplicationContextAware, ServletContextAware {
    	//由用户注入: web.ignoring().antMatchers("/***")
    	private final List<RequestMatcher> ignoredRequests = new ArrayList<>();
    	private IgnoredRequestConfigurer ignoredRequestRegistry; //new IgnoredRequestConfigurer(ctx)
    	
    
    	private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<>();//由WebSecurityConfiguration初始化
    	private FilterSecurityInterceptor filterSecurityInterceptor;//由WebSecurityConfiguration初始化
    	
    	@Autowired
    	private HttpFirewall httpFirewall;
    	
    	@Autowired
    	private RequestRejectedHandler requestRejectedHandler;
    	private WebInvocationPrivilegeEvaluator privilegeEvaluator; //初始化完成后,被WebSecurityConfiguration @Bean 注入;
    	
    	private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
    	private SecurityExpressionHandler<FilterInvocation> expressionHandler = this.defaultWebSecurityExpressionHandler;//初始化完成后,被WebSecurityConfiguration @Bean 注入;
    	private Runnable postBuildAction = () -> {};
    	
    	@Override
    	protected Filter performBuild() throws Exception {
    	
    		int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
    		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize); //
    		List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
    		for (RequestMatcher ignoredRequest : this.ignoredRequests) {
    			SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
    			securityFilterChains.add(securityFilterChain);//将ignoredRequest 添加在第1位
    			requestMatcherPrivilegeEvaluatorsEntries
    					.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); //2
    		}
    		//for循环build securityFilterChains
    		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
    			SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
    			securityFilterChains.add(securityFilterChain);
    			requestMatcherPrivilegeEvaluatorsEntries
    					.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); 
    		}
    		
    		//3.
    		if (this.privilegeEvaluator == null) {
    			this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
    					requestMatcherPrivilegeEvaluatorsEntries);
    		}
    		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
    		filterChainProxy.setFirewall(this.httpFirewall);
    		filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
    		filterChainProxy.afterPropertiesSet();
    
    		Filter result = filterChainProxy;
    	
    		this.postBuildAction.run();
    		return result;
    	}
    	
    	//2
    	private RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> getRequestMatcherPrivilegeEvaluatorsEntry(
    			SecurityFilterChain securityFilterChain) {
    		List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = new ArrayList<>();
    		for (Filter filter : securityFilterChain.getFilters()) {
    			if (filter instanceof FilterSecurityInterceptor) {
    				DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
    						(FilterSecurityInterceptor) filter);
    				privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
    				continue;
    			}
    			if (filter instanceof AuthorizationFilter) {
    				AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
    						.getAuthorizationManager();
    				AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
    						authorizationManager);
    				privilegeEvaluators.add(evaluator);
    			}
    		}
    		return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);//2 match --> privilegeEvaluators
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    3.3.2.1 关键接口: WebInvocationPrivilegeEvaluator
    public interface WebInvocationPrivilegeEvaluator {
        boolean isAllowed(String uri, Authentication authentication);
    
        boolean isAllowed(String contextPath, String uri, String method, Authentication authentication);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    类图
    RequestMatcherDelegatingWebInvocationPrivilegeEvaluator

    3.3.2.2 关键类:RequestMatcherDelegatingWebInvocationPrivilegeEvaluator
    public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator
    		implements WebInvocationPrivilegeEvaluator, ServletContextAware {
    
    	//构造函数 set
    	private final List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> delegates;
    
    	
    	@Override
    	public boolean isAllowed(String uri, Authentication authentication) {
    		List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = getDelegate(null, uri, null);
    		//for-each privilegeEvaluators .isAllowed(uri, authentication) 略...
    		return true;
    	}
    
    
    	@Override
    	public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
    		List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = getDelegate(contextPath, uri, method);
    		//for-each privilegeEvaluators .isAllowed(contextPath, uri, method, authentication); 略...
    		return true;
    	}
    
    	private List<WebInvocationPrivilegeEvaluator> getDelegate(String contextPath, String uri, String method) {
    		//filter 匹配的 WebInvocationPrivilegeEvaluator
    		FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
    		for (RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> delegate : this.delegates) {
    			if (delegate.getRequestMatcher().matches(filterInvocation.getHttpRequest())) {
    				return delegate.getEntry();
    			}
    		}
    		return Collections.emptyList();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3.4总体处理流程(细)

    3.4.1.FilterChainProxy.doFilter()

    public class FilterChainProxy extends GenericFilterBean {
    	private List<SecurityFilterChain> filterChains;
        private HttpFirewall firewall;
        private RequestRejectedHandler requestRejectedHandler;
    	
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
           try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                this.doFilterInternal(request, response, chain); //1
           } catch (Exception var11) {
           		//略....
           		this.requestRejectedHandler.handle((HttpServletRequest)request, (HttpServletResponse)response, (RequestRejectedException)requestRejectedException);
            } finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        }
    	
    	private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request); //1
            HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);//2
            List<Filter> filters = this.getFilters((HttpServletRequest)firewallRequest);
        
    		//遍历filterchain dofilter....
          	VirtualFilterChain virtualFilterChain = new 	VirtualFilterChain(firewallRequest, chain, filters);
            virtualFilterChain.doFilter(firewallRequest, firewallResponse);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    3.4.1.1关键接口: HttpFirewall

    https://docs.spring.io/spring-security/reference/servlet/exploits/firewall.html
    在这里插入图片描述
    使用样例

    @Bean
    public StrictHttpFirewall httpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST"));
        return firewall;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.4.2.Filter.doFilter()

    3.4.2.1 UsernamePasswordAuthenticationFilter

    以**UsernamePasswordAuthenticationFilter**为例

    UsernamePasswordAuthenticationFilter.doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    	AbstractAuthenticationProcessingFilter.doFilter(request,response,chain)
    		doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
    			UsernamePasswordAuthenticationFilter.attemptAuthentication()
    
    
    ///
    public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
    		implements ApplicationEventPublisherAware, MessageSourceAware {
    
    	private AuthenticationManager authenticationManager;	
    
    	//1.
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);//2.
    	}
    
    	//2.
    	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		if (!requiresAuthentication(request, response)) { //3.
    			chain.doFilter(request, response);
    			return;
    		}
    		Authentication authenticationResult = attemptAuthentication(request, response);//4 由子类实现
    		if (authenticationResult == null) {
    			return;
    		}
    		this.sessionStrategy.onAuthentication(authenticationResult, request, response);
    		
    		if (this.continueChainBeforeSuccessfulAuthentication) { //default false;
    			chain.doFilter(request, response);
    		}
    		successfulAuthentication(request, response, chain, authenticationResult); //5
    	}
    
    	
    	//3.
    	protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
    		if (this.requiresAuthenticationRequestMatcher.matches(request)) {
    			return true;
    		}
    		return false;
    	}
    
    
    	//4
    	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
    			Authentication authResult) throws IOException, ServletException {
    		SecurityContext context = SecurityContextHolder.createEmptyContext();
    		context.setAuthentication(authResult);
    		SecurityContextHolder.setContext(context);
    		this.securityContextRepository.saveContext(context, request, response);
    		
    		this.successHandler.onAuthenticationSuccess(request, response, authResult);
    	}
    }
    
    /
    //4.
    public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
        public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
        private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST");
        private String usernameParameter = "username";
        private String passwordParameter = "password";
        private boolean postOnly = true;
    
        public UsernamePasswordAuthenticationFilter() {
            super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
        }
    
        public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
            super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager);
        }
    
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (this.postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            } else {
                String username = this.obtainUsername(request);
                String password = this.obtainPassword(request);
                
                //request类型为:UsernamePasswordAuthenticationToken,且为unauthenticated
                UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
                this.setDetails(request, authRequest);
                //交由AuthenticationManager来进行认证: 
                return this.getAuthenticationManager().authenticate(authRequest);
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    4.AuthenticationManager authentication(认证)

    4.1 AuthenticationManager初始化

    AuthenticationManager是在AuthenticationConfiguration中由@beanAuthenticationManagerBuilder.build()初始化。
    AuthenticationManagerBuilder的具体类型为:DefaultPasswordEncoderAuthenticationManagerBuilder
    同时AuthenticationManagerBuilder.apply了

    • EnableGlobalAuthenticationAutowiredConfigurer
    • InitializeUserDetailsBeanManagerConfigurer : 注入UserDetailsService
    • InitializeAuthenticationProviderBeanManagerConfigurer

    4.1.1 关键配置

    4.1.1.1 InitializeUserDetailsBeanManagerConfigurer
    class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
    
    	@Override
    	public void init(AuthenticationManagerBuilder auth) throws Exception {
    		auth.apply(new InitializeUserDetailsManagerConfigurer());
    	}
    
    	class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
    
    		@Override
    		public void configure(AuthenticationManagerBuilder auth) throws Exception {
    			if (auth.isConfigured()) {
    				return;
    			}
    			UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
    			if (userDetailsService == null) {
    				return;
    			}
    			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
    			UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
    			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    			provider.setUserDetailsService(userDetailsService); //注入UserDetailsService
    			if (passwordEncoder != null) {
    				provider.setPasswordEncoder(passwordEncoder);
    			}
    			if (passwordManager != null) {
    				provider.setUserDetailsPasswordService(passwordManager);
    			}
    			provider.afterPropertiesSet();
    			auth.authenticationProvider(provider); //添加DaoAuthenticationProvider
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    4.1.1.2 InitializeUserDetailsBeanManagerConfigurer
    @Order(InitializeAuthenticationProviderBeanManagerConfigurer.DEFAULT_ORDER)
    class InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
    
    	@Override
    	public void init(AuthenticationManagerBuilder auth) throws Exception {
    		auth.apply(new InitializeAuthenticationProviderManagerConfigurer());
    	}
    
    	class InitializeAuthenticationProviderManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
    
    		@Override
    		public void configure(AuthenticationManagerBuilder auth) {
    			if (auth.isConfigured()) {
    				return;
    			}
    			AuthenticationProvider authenticationProvider = getBeanOrNull(AuthenticationProvider.class); //注入其他AuthenticationProvider
    			if (authenticationProvider == null) {
    				return;
    			}
    			auth.authenticationProvider(authenticationProvider);
    		}
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4.1.2.DefaultPasswordEncoderAuthenticationManagerBuilder.build()

    4.1.2.1. 类图

    在这里插入图片描述

    4.1.2.2.DefaultPasswordEncoderAuthenticationManagerBuilder.build()
    //1.执行流程
    DefaultPasswordEncoderAuthenticationManagerBuilder.build()
    	AbstractSecurityBuilder.build()
    		AbstractConfiguredSecurityBuilder.doBuild()
    			//beforeInit(); init(); beforeConfigure(); configure(); 略
    			performBuild();
    				AuthenticationManagerBuilder.performBuild()
    //
    public class AuthenticationManagerBuilder
    		extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
    		implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
    			private AuthenticationManager parentAuthenticationManager;
    			private List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
    			private UserDetailsService defaultUserDetailsService;
    
    	@Override
    	protected ProviderManager performBuild() throws Exception {
    		
    		// AuthenticationManager具体类型为 ProviderManager
    		ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
    				this.parentAuthenticationManager);
    		providerManager = postProcess(providerManager);
    		return providerManager;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    4.1.2.3 ProviderManager类图

    在这里插入图片描述

    4.3 ProviderManager.authenticate()

    public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
    
    	private List<AuthenticationProvider> providers = Collections.emptyList();
    	private AuthenticationManager parent;
    
    
    	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    		Class<? extends Authentication> toTest = authentication.getClass();
    		Authentication result = null;
    		Authentication parentResult = null;
    
    		for (AuthenticationProvider provider : getProviders()) { //获取AuthenticationProvider
    			if (!provider.supports(toTest)) {
    				continue;
    			}
    	
    			result = provider.authenticate(authentication);
    			if (result != null) {
    				copyDetails(authentication, result);
    				break;
    			}
    		}
    		if (result == null && this.parent != null) {
    			// Allow the parent to try.
    			parentResult = this.parent.authenticate(authentication);
    			result = parentResult;
    			
    		}
    		if (result != null) {
    			if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
    				// Authentication is complete. Remove credentials and other secret data
    				// from authentication
    				((CredentialsContainer) result).eraseCredentials();
    			}
    
    			return result;
    		}
    		throw lastException;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    4.3.1 AuthenticationProvider

    4.3.1.1 接口定义
    public interface AuthenticationProvider {
    	Authentication authenticate(Authentication authentication) throws AuthenticationException;
    	boolean supports(Class<?> authentication);
    }
    
    • 1
    • 2
    • 3
    • 4
    4.3.1.2 类图

    在这里插入图片描述

    4.3.1.3 DaoAuthenticationProvider 示例

    在前文有提到,在build AuthenticationMananger时,会注入一个DaoAuthenticationProvider

    public abstract class AbstractUserDetailsAuthenticationProvider
    		implements AuthenticationProvider, InitializingBean, MessageSourceAware {
    
    	 
    	private UserCache userCache = new NullUserCache(); //可通过set设置
    	private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks(); //可通过set设置
    	private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();//可通过set设置
    
    
    	//仅支持UsernamePasswordAuthenticationToken类型的请求
    	public boolean supports(Class<?> authentication) {
    		return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    	}
    
    	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    		String username = determineUsername(authentication);
    		UserDetails user = this.userCache.getUserFromCache(username); //优先从缓存获取
    		if (user == null) {
    			user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); //由子类实现 1
    			Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
    		}
    		
    		this.preAuthenticationChecks.check(user);
    		additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); //子类实现 2
    		this.postAuthenticationChecks.check(user);
    
    		this.userCache.putUserInCache(user); //set 缓存
    		
    		Object principalToReturn = user //认证信息	
    		return createSuccessAuthentication(principalToReturn, authentication, user); //子类实现3, 父类提供默认实现4
    	}
    
    	//4
    	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
    			UserDetails user) {
    		//getAuthorities: 可以理解为角色信息  或者权限码
    		UsernamePasswordAuthenticationToken result = UsernamePasswordAuthenticationToken.authenticated(principal,
    				authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
    		result.setDetails(authentication.getDetails());
    		this.logger.debug("Authenticated user");
    		return result;
    	}
    }
    
    public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    
    	private UserDetailsService userDetailsService;
    
    	//1. 查询username信息
    	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
    			throws AuthenticationException {
    		UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
    		if (loadedUser == null) {
    			throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
    		}
    		return loadedUser;
    	}
    
    	//2. 验证密码
    	protected void additionalAuthenticationChecks(UserDetails userDetails,
    			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    		if (authentication.getCredentials() == null) {
    			throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
    		}
    		String presentedPassword = authentication.getCredentials().toString(); //登录时,输入的密码
    		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {//加密输入的密码 并于查询出来的密码做匹配验证
    			throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
    		}
    	}
    
    	//4.
    	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
    			UserDetails user) {
    		//默认为false:::: 自动更新密码???
    		boolean upgradeEncoding = this.	 != null&& this.passwordEncoder.upgradeEncoding(user.getPassword());
    		if (upgradeEncoding) {
    			String presentedPassword = authentication.getCredentials().toString();
    			String newPassword = this.passwordEncoder.encode(presentedPassword);
    			user = this.userDetailsPasswordService.updatePassword(user, newPassword);
    		}
    		return super.createSuccessAuthentication(principal, authentication, user);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    4.3.2 Authentication

    4.3.2.1. 接口定义
    public interface Authentication extends Principal, Serializable {
    	//授权码 && 角色码 .... **后续鉴权流程会使用到**
    	Collection<? extends GrantedAuthority> getAuthorities();
    
    	Object getCredentials();
    	Object getDetails();
    	Object getPrincipal();
    	boolean isAuthenticated();
    	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    4.3.2.2. UsernamePasswordAuthenticationToken 类图

    在这里插入图片描述



    5. authorization(鉴权)

    https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/index.html

    5.1 架构

    5.1.1. AuthorizationManager

    5.1.1.1接口定义
    public interface AuthorizationManager<T> {
    	//若没有权限,直接返回"Access Denied"
    	default void verify(Supplier<Authentication> authentication, T object) {
    		AuthorizationDecision decision = check(authentication, object);
    		if (decision != null && !decision.isGranted()) {
    			throw new AccessDeniedException("Access Denied");
    		}
    	}
    	@Nullable
    	AuthorizationDecision check(Supplier<Authentication> authentication, T object);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    5.1.1.2.类图

    在这里插入图片描述

    5.1.2 AccessDecisionManager

    5.1.2.1 AccessDecisionVoter
    public interface AccessDecisionVoter<S> {
    	int ACCESS_GRANTED = 1;
    	int ACCESS_ABSTAIN = 0;
    	int ACCESS_DENIED = -1;
    
    	boolean supports(ConfigAttribute attribute);
    	boolean supports(Class<?> clazz);
    
    	//投票; 交由AccessDecisionManager统计结果,最终决定是否通过鉴权
    	int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    5.1.2.1.AccessDecisionManager接口定义
    public interface AccessDecisionManager {
    	//决定是否通过鉴权,如果未通过则抛出异常
    	void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
    			throws AccessDeniedException, InsufficientAuthenticationException;
    	boolean supports(ConfigAttribute attribute);
    	boolean supports(Class<?> clazz);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5.1.2.2 类图

    AccessDecisionManager

    5.2. 鉴权

    5.2.1. 通过AuthorizationFilter鉴权

    5.2.1.1 流程图

    在这里插入图片描述

    5.2.1.2 http启用authorize

    更多方式参照:https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/authorize-http-requests.html

    @Bean
    SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
        http ...
        .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated();) //1
        return http.build();
    }
    
    
    	public HttpSecurity authorizeHttpRequests(
    			Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer)
    			throws Exception {
    		authorizeHttpRequestsCustomizer
    				.customize(getOrApply(new AuthorizeHttpRequestsConfigurer<>(context)).getRegistry());
    		return HttpSecurity.this;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    5.2.1.3 AuthorizeHttpRequestsConfigurer.configure()
    public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
    		extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {
    
    	private final AuthorizationManagerRequestMatcherRegistry registry;
    
    	public AuthorizeHttpRequestsConfigurer(ApplicationContext context) {
    		this.registry = new AuthorizationManagerRequestMatcherRegistry(context);
    	}
    
    	@Override
    	public void configure(H http) {
    		AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
    		AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager); 
    		authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
    		http.addFilter(postProcess(authorizationFilter)); //2.注册 extends AbstractRequestMatcherRegistry {
    AuthorizationFilter
    	}
    
    	public final class AuthorizationManagerRequestMatcherRegistry extends AbstractRequestMatcherRegistry<AuthorizedUrl> {
    			
    		private final RequestMatcherDelegatingAuthorizationManager.Builder managerBuilder = RequestMatcherDelegatingAuthorizationManager.builder();
    				
    	
    		private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
    			return postProcess(this.managerBuilder.build());
    		}
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    5.2.2. 通过FilterSecurityInterceptor鉴权

    https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/authorize-requests.html

    5.2.2.1 流程图

    在这里插入图片描述

    5.2.2.2常见注解

    https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/expression-based.html#el-common-built-in

    • hasRole(String role)
    • hasAnyRole(String…​ roles)
    • hasAuthority(String authority)
    • hasAnyAuthority(String…​ authorities)
    • isAuthenticated()
    • permitAll
    • denyAll
    • hasPermission(Object target, Object permission)
    • hasPermission(Object targetId, String targetType, Object permission)
    5.2.2.3 配置
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    	http
    		// ...
    		.authorizeRequests(authorize -> authorize                                  
    			.mvcMatchers("/resources/**", "/signup", "/about").permitAll()         
    			.mvcMatchers("/admin/**").hasRole("ADMIN")                             
    			.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")    //1.http.register类型为:ExpressionInterceptUrlRegistry
    			.anyRequest().denyAll()                                                
    		);
    	return http.build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ExpressionInterceptUrlRegistry.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")

    5.2.2.4 配置拆解1-ExpressionInterceptUrlRegistry.mvcMatchers()
    //see  HttpSecurity.authorizeRequests()
    public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
    		extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
    	//1.
    	public final class ExpressionInterceptUrlRegistry extends
    			ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
    
    		public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) {
    			return mvcMatchers(null, patterns);
    		}
    
    		public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
    			return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));//2
    		}
    	}
    
    	//2
    	public final class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
    		private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> requestMatchers) {
    			super(requestMatchers);//3
    		}
    	}
    
    	//3	
    	public class AuthorizedUrl {
    		private List<? extends RequestMatcher> requestMatchers;
    
    
    		AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
    			this.requestMatchers = requestMatchers;
    		}
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    返回对象为: MvcMatchersAuthorizedUrl

    5.2.2.5 配置拆解2-MvcMatchersAuthorizedUrl.access()
    //see  HttpSecurity.authorizeRequests()
    public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
    		extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
    
    	static final String permitAll = "permitAll";
    	private static final String denyAll = "denyAll";
    	private static final String anonymous = "anonymous";
    	private static final String authenticated = "authenticated";
    	private static final String fullyAuthenticated = "fullyAuthenticated";
    	private static final String rememberMe = "rememberMe";
    	private final String rolePrefix;
    	private final ExpressionInterceptUrlRegistry REGISTRY;
    	private SecurityExpressionHandler<FilterInvocation> expressionHandler;
    
    	public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
    		//set rolePrefix略,默认为为"ROLE_";
    		this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
    	}
    
    
    	//2
    	private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers,
    			Collection<ConfigAttribute> configAttributes) {
    		for (RequestMatcher requestMatcher : requestMatchers) {
    			this.REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
    		}
    	}
    
    
    
    	public class AuthorizedUrl {
    
    		private List<? extends RequestMatcher> requestMatchers;
    
    		private boolean not;
    
    		public ExpressionInterceptUrlRegistry hasRole(String role) {
    			return access(ExpressionUrlAuthorizationConfigurer
    					.hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role));
    		}
    
    	
    		public ExpressionInterceptUrlRegistry hasAnyRole(String... roles) {
    			return access(ExpressionUrlAuthorizationConfigurer
    					.hasAnyRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, roles));
    		}
    
    		public ExpressionInterceptUrlRegistry hasAuthority(String authority) {
    			return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
    		}
    
    		public ExpressionInterceptUrlRegistry permitAll() {
    			return access(permitAll);
    		}
    
    		
    		public ExpressionInterceptUrlRegistry authenticated() {
    			return access(authenticated);//1
    		}
    
    
    		public ExpressionInterceptUrlRegistry access(String attribute) {
    			if (this.not) {
    				attribute = "!" + attribute;
    			}
    			//string -> SecurityConfig(ConfigAttribute)
    			interceptUrl(this.requestMatchers, SecurityConfig.createList(attribute)); 
    			return ExpressionUrlAuthorizationConfigurer.this.REGISTRY;
    		}
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    5.2.2.6 ExpressionUrlAuthorizationConfigurer类图

    在这里插入图片描述

    5.2.2.7 ExpressionUrlAuthorizationConfigurer.configure()
    public abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
    		extends AbstractHttpConfigurer<C, H> {
    
    	private AccessDecisionManager accessDecisionManager;
    
    
    	@Override
    	public void configure(H http) throws Exception {
    		FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http); //1. 子类实现
    	
    		FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource,http.getSharedObject(AuthenticationManager.class)); //2
    		securityInterceptor = postProcess(securityInterceptor);
    		http.addFilter(securityInterceptor);
    		http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
    	}
    
    
    	//2
    	private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,
    			FilterInvocationSecurityMetadataSource metadataSource, AuthenticationManager authenticationManager)
    			throws Exception {
    		FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
    		securityInterceptor.setSecurityMetadataSource(metadataSource);
    
    		//默认为:this.createDefaultAccessDecisionManager()//3
    		securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
    		securityInterceptor.setAuthenticationManager(authenticationManager);
    		securityInterceptor.afterPropertiesSet();
    		return securityInterceptor;
    	}
    
    
    	//3
    	private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
    		AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));//4. 由子类实现
    		return postProcess(result);
    	}
    }
    
    /子类
    public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
    		extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
    
    	private final ExpressionInterceptUrlRegistry REGISTRY;
    	private SecurityExpressionHandler<FilterInvocation> expressionHandler;
    
    	public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
    		this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
    	}
    
    	private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers,
    			Collection<ConfigAttribute> configAttributes) {
    		for (RequestMatcher requestMatcher : requestMatchers) {
    			this.REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
    		}
    	}
    
    	
    	//4
    	@Override
    	List<AccessDecisionVoter<?>> getDecisionVoters(H http) {
    		List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
    		WebExpressionVoter expressionVoter = new WebExpressionVoter();
    		expressionVoter.setExpressionHandler(getExpressionHandler(http));//5.类型为DefaultWebSecurityExpressionHandler
    		decisionVoters.add(expressionVoter);//类型为WebExpressionVoter
    		return decisionVoters;
    	}
    	
    	//1.
    	@Override
    	ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(H http) {
    		LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = this.REGISTRY.createRequestMap();
    		return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, getExpressionHandler(http));
    	}
    
    	//5
    	private SecurityExpressionHandler<FilterInvocation> getExpressionHandler(H http) {
    		
    		DefaultWebSecurityExpressionHandler defaultHandler = new DefaultWebSecurityExpressionHandler();
    		AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
    		defaultHandler.setTrustResolver(trustResolver);
    		ApplicationContext context = http.getSharedObject(ApplicationContext.class);
    		String[] roleHiearchyBeanNames = context.getBeanNamesForType(RoleHierarchy.class);
    		
    		//设置RoleHierarchy 以及rolePrefix...
    		defaultHandler.setRoleHierarchy(context.getBean(roleHiearchyBeanNames[0], RoleHierarchy.class));		
    defaultHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
    			
    		//在GlobalMethodSecurityConfiguration中定义,略......
    		String[] permissionEvaluatorBeanNames = context.getBeanNamesForType(PermissionEvaluator.class);
    		PermissionEvaluator permissionEvaluator = context.getBean(permissionEvaluatorBeanNames[0],PermissionEvaluator.class);
    		defaultHandler.setPermissionEvaluator(permissionEvaluator);
    
    		this.expressionHandler = postProcess(defaultHandler);
    		return this.expressionHandler;
    	}
    
    }		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    5.2.2.8 重要接口: SecurityExpressionHandler

    在这里插入图片描述

    5.2.2.9 重要接口: PermissionEvaluator
    public interface PermissionEvaluator extends AopInfrastructureBean {
    
    	boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);
    
    	boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5.2.2.10 AffirmativeBased.decide()
    public class AffirmativeBased extends AbstractAccessDecisionManager {
    
    	public AffirmativeBased(List<AccessDecisionVoter<?>> decisionVoters) {
    		super(decisionVoters);
    	}
    
    	@Override
    	@SuppressWarnings({ "rawtypes", "unchecked" })
    	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
    			throws AccessDeniedException {
    		int deny = 0;
    		for (AccessDecisionVoter voter : getDecisionVoters()) { //for-each 进行投票
    			int result = voter.vote(authentication, object, configAttributes);
    			switch (result) {
    			case AccessDecisionVoter.ACCESS_GRANTED:
    				return;
    			case AccessDecisionVoter.ACCESS_DENIED:
    				deny++;
    				break;
    			default:
    				break;
    			}
    		}
    		if (deny > 0) {
    			throw new AccessDeniedException(this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
    					
    		}
    		//到这里,所有人全部期权;
    		checkAllowIfAllAbstainDecisions();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    5.2.2.11 WebExpressionVoter.vote()
    public class WebExpressionVoter implements AccessDecisionVoter<FilterInvocation> {
    		private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
    
    	public int vote(Authentication authentication, FilterInvocation filterInvocation,
    			Collection<ConfigAttribute> attributes) {
    		//attribute instanceof WebExpressionConfigAttribute
    		WebExpressionConfigAttribute webExpressionConfigAttribute = findConfigAttribute(attributes);
    		if (webExpressionConfigAttribute == null) {
    			return ACCESS_ABSTAIN;
    		}
    		//2.webExpressionConfigAttribute.postProcess() 
    		//返回:new VariableEvaluationContext(WebSecurityExpressionRoot.class, invocation.getHttpRequest())
    		EvaluationContext ctx = webExpressionConfigAttribute.postProcess(
    				this.expressionHandler.createEvaluationContext(authentication, filterInvocation), filterInvocation); //类型为:DefaultWebSecurityExpressionHandler1,返回值为WebSecurityExpressionRoot
    	
    		//3
    		boolean granted = ExpressionUtils.evaluateAsBoolean(webExpressionConfigAttribute.getAuthorizeExpression(), ctx);
    		if (granted) {
    			return ACCESS_GRANTED;
    		}
    		return ACCESS_DENIED;
    	}
    
    	private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
    		for (ConfigAttribute attribute : attributes) {
    			if (attribute instanceof WebExpressionConfigAttribute) {
    				return (WebExpressionConfigAttribute) attribute;
    			}
    		}
    		return null;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    5.2.2.12.DefaultWebSecurityExpressionHandler.createSecurityExpressionRoot()
    public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation>
    		implements SecurityExpressionHandler<FilterInvocation> {
    			
    	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
    	private String defaultRolePrefix = "ROLE_";
    
    	//在ExpressionUrlAuthorizationConfigurer#getExpressionHandler()中定义
    	protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,FilterInvocation fi) {
    		WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
    		root.setPermissionEvaluator(getPermissionEvaluator());
    		root.setTrustResolver(this.trustResolver);
    		root.setRoleHierarchy(getRoleHierarchy());
    		root.setDefaultRolePrefix(this.defaultRolePrefix);
    		return root; //返回
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    5.2.2.13 ExpressionUtils.evaluateAsBoolean(context,invocation)
    public final class ExpressionUtils {
    
    	private ExpressionUtils() {
    	}
    
    	public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
    		//ctx:new  VariableEvaluationContext(new WebSecurityExpressionRoot())`
    		//expr: SpelExpression 调用SPEL表达式
    		return expr.getValue(ctx, Boolean.class);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    5.2.2.14 重要接口-WebSecurityExpressionRoot

    在这里插入图片描述

    5.2.2.15 重要接口-VariableEvaluationContext(略)

    5.2.3. 通过Expression鉴权

    https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/expression-based.html

    5.2.3.2 Referring to Beans in Web Security Expressions
    //1.定义工具类
    public class WebSecurityAuthz {
    		public boolean check(Authentication authentication, HttpServletRequest request) {
    				...
    		}
    }
    
    //2. httpsecurity注册
    http
        .authorizeHttpRequests(authorize -> authorize
            .antMatchers("/user/**").access("@WebSecurityAuthz.check(authentication,request)")
            ...
        )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    5.2.3.3 Path Variables in Web Security Expressions
    public class webSecurityAuthz2 {
    		public boolean checkUserId(Authentication authentication, int id) {
    				...
    		}
    }
    
    http
    	.authorizeHttpRequests(authorize -> authorize
    		.antMatchers("/user/{userId}/**").access("@webSecurityAuthz2.checkUserId(authentication,#userId)")
    		...
    	);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    5.2.3.4 Method Security Expressions

    启用global-method-security

    <global-method-security pre-post-annotations="enabled"/>
    
    • 1
    @PreAuthorize("hasRole('USER')")
    public void create(Contact contact)
    
    @PreAuthorize("hasPermission(#contact, 'admin')")
    public void deletePermission(Contact contact, Sid recipient, Permission permission);
    
    @PreAuthorize("#c.name == authentication.name")
    public void doSomething(@P("c") Contact contact);
    
    
    @PreAuthorize("#n == authentication.name")
    Contact findContactByName(@Param("n") String name);
    
    @PreAuthorize("#contact.name == authentication.name")
    public void doSomething(Contact contact);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    5.2.3.5 @PreFilter and @PostFilter

    在使用@PostFilter注释时,Spring Security会遍历返回的集合或映射,并删除所有提供的表达式为false的元素。对于数组,将返回一个新的数组实例,其中包含筛选后的元素。

    @PreAuthorize("hasRole('USER')")
    @PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
    public List<Contact> getAll();
    
    
    • 1
    • 2
    • 3
    • 4


    6.methodSecurity 流程分析

    添加链接描述

    6.1.@EnableGlobalMethodSecurity

    6.1.1 接口定义

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import({ GlobalMethodSecuritySelector.class }) //通常使用:@GlobalMethodSecurityConfiguration
    @EnableGlobalAuthentication
    @Configuration
    public @interface EnableGlobalMethodSecurity {
    	boolean prePostEnabled() default false;
    	boolean securedEnabled() default false;
    	boolean jsr250Enabled() default false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6.1.2.GlobalMethodSecurityConfiguration

    public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInitializingSingleton, BeanFactoryAware {
    
    	private DefaultMethodSecurityExpressionHandler defaultMethodExpressionHandler = new DefaultMethodSecurityExpressionHandler(); 
    	private AuthenticationManager authenticationManager;
    	private AuthenticationManagerBuilder auth;
    
    	private MethodSecurityExpressionHandler expressionHandler;
    	private MethodSecurityInterceptor methodSecurityInterceptor;
    	
    	@Bean
    	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    	public MethodSecurityMetadataSource methodSecurityMetadataSource() {
    		List<MethodSecurityMetadataSource> sources = new ArrayList<>();
    		ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(getExpressionHandler());
    				
    		MethodSecurityMetadataSource customMethodSecurityMetadataSource = customMethodSecurityMetadataSource();
    		sources.add(customMethodSecurityMetadataSource);
    		
    		sources.add(new PrePostAnnotationSecurityMetadataSource(attributeFactory));
    		sources.add(new SecuredAnnotationSecurityMetadataSource());
    		sources.add(jsr250MethodSecurityMetadataSource);
    		return new DelegatingMethodSecurityMetadataSource(sources);
    	}
    	
    	@Bean
    	public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
    		this.methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor(): new MethodSecurityInterceptor();
    		this.methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager()); //1.
    		this.methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());//2.
    		this.methodSecurityInterceptor.setSecurityMetadataSource(methodSecurityMetadataSource);
    		
    		// runAsManager default null;
    		return this.methodSecurityInterceptor;
    	}
    	
    
    	@Override
    	public void afterSingletonsInstantiated() {
    		initializeMethodSecurityInterceptor(); //内部调用:methodSecurityInterceptor.setAuthenticationManager(authenticationManager())
    
    		PermissionEvaluator permissionEvaluator = getSingleBeanOrNull(PermissionEvaluator.class);
    		this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluator);
    
    		RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class);
    		this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
    		AuthenticationTrustResolver trustResolver = getSingleBeanOrNull(AuthenticationTrustResolver.class);
    		if (trustResolver != null) {
    			this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
    		}
    		
    		//设置rolePrefix 略...
    
    		this.defaultMethodExpressionHandler = this.objectPostProcessor.postProcess(this.defaultMethodExpressionHandler);
    	}
    
    
    	protected AccessDecisionManager accessDecisionManager() {
    		List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
    		if (prePostEnabled()) {
    			ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
    			expressionAdvice.setExpressionHandler(getExpressionHandler());
    			decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice)); // add PreInvocationAuthorizationAdviceVoter
    		}
    		
    		RoleVoter roleVoter = new RoleVoter();
    		GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(GrantedAuthorityDefaults.class);
    		if (grantedAuthorityDefaults != null) {
    			roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
    		}
    		decisionVoters.add(roleVoter);
    		decisionVoters.add(new AuthenticatedVoter()); // add AuthenticatedVoter
    		return new AffirmativeBased(decisionVoters);
    	}
    	
    	//由子类覆盖,达到自定义MethodSecurityExpressionHandler的目的;
    	protected MethodSecurityExpressionHandler createExpressionHandler() {
    		return this.defaultMethodExpressionHandler;
    	}
    
    	protected final MethodSecurityExpressionHandler getExpressionHandler() {
    		if (this.expressionHandler == null) {
    			this.expressionHandler = createExpressionHandler();
    		}
    		return this.expressionHandler;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    6.2. 认证+鉴权流程

    通过AOP,拦截带有特定注解的方法

    • @PreAuthorize
    • @PostAuthorize
    • @PreFilter
    • @PostFilter
      通过MethodSecurityInterceptor 拦截.

    6.2.1.重要接口- MethodSecurityMetadataSource

    6.2.1.1 类图

    在这里插入图片描述

    6.2.1.2 PrePostAnnotationSecurityMetadataSource
    public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
    
    	@Override
    	public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
    		if (method.getDeclaringClass() == Object.class) {
    			return Collections.emptyList();
    		}
    		PreFilter preFilter = findAnnotation(method, targetClass, PreFilter.class);
    		PreAuthorize preAuthorize = findAnnotation(method, targetClass, PreAuthorize.class);
    		PostFilter postFilter = findAnnotation(method, targetClass, PostFilter.class);
    		PostAuthorize postAuthorize = findAnnotation(method, targetClass, PostAuthorize.class);
    		
    		
    		ArrayList<ConfigAttribute> attrs = new ArrayList<>(2);
    		PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute,
    				filterObject, preAuthorizeAttribute);
    		attrs.add(pre);
    		PostInvocationAttribute post = this.attributeFactory.createPostInvocationAttribute(postFilterAttribute,
    				postAuthorizeAttribute);
    		attrs.add(post);
    		return attrs;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    6.2.2.重要接口:MethodInterceptor

    6.2.2.1 类图

    在这里插入图片描述

    6.2.2.2.MethodSecurityInterceptor
    public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {
    
    	private MethodSecurityMetadataSource securityMetadataSource;
    
    	@Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		InterceptorStatusToken token = super.beforeInvocation(mi); //1.AbstractSecurityInterceptor.beforeInvocation()
    		Object result;
    		try {
    			result = mi.proceed();
    		}
    		finally {
    			super.finallyInvocation(token); //2.
    		}
    		return super.afterInvocation(token, result);//3.
    	}
    
    }
    
    public abstract class AbstractSecurityInterceptor
    		implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware {
    
    	private AccessDecisionManager accessDecisionManager;
    	private AfterInvocationManager afterInvocationManager;
    	private AuthenticationManager authenticationManager = new NoOpAuthenticationManager();
    	private RunAsManager runAsManager = new NullRunAsManager();		
    
    
    	protected InterceptorStatusToken beforeInvocation(Object object) {
    		
    		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
    		
    		Authentication authenticated = authenticateIfRequired();
    		
    		attemptAuthorization(object, attributes, authenticated);	//1.1	
    		return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
    
    	}
    
    	//1.1
    	private void attemptAuthorization(Object object, Collection<ConfigAttribute> attributes,
    			Authentication authenticated) {
    		//1.1.1
    		this.accessDecisionManager.decide(authenticated, object, attributes);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    accessDecisionManager.decide 逻辑前文已经有说明,这里不再赘述.



    9.自定义拓展

    9.1 自定义验证规则

    9.1.1 实现的功能

        @PreAuthorize("isHuaWeiLogin() || isAppleLoginAndHasPermissions('mobile:add'))")
        public void xxx(){}
    
    
    • 1
    • 2
    • 3

    9.1.2 configuration

    @Configuration
    public class WbsGlobalSecurityConfig extends GlobalMethodSecurityConfiguration {
    
    
        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
            PrivilegeMethodSecurityExpressionHandler expressionHandler = new PrivilegeMethodSecurityExpressionHandler();
            expressionHandler.setPermissionEvaluator(null);
            return expressionHandler;
        }
    
        public class PrivilegeMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
            @Override
            protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
                PrivilegeMethodSecurityExpressionRoot root = new PrivilegeMethodSecurityExpressionRoot(authentication);
                root.setPermissionEvaluator(this.getPermissionEvaluator());
                root.setRoleHierarchy(this.getRoleHierarchy());
                return root;
            }
        }
    
        public class PrivilegeMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
    
            @Getter @Setter
            private Object filterObject;
    
            @Getter @Setter
            private Object returnObject;
            private Object target;
    
            PrivilegeMethodSecurityExpressionRoot(Authentication authentication) {
                super(authentication);
            }
    
            void setThis(Object target) {
                this.target = target;
            }
    
            public Object getThis() {
                return this.target;
            }
    
            private Map<String, Object> orgHelperMocked = Collections.emptyMap();
            public boolean isAppleLogin() {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication != null && authentication instanceof AppleUserAuthenticationToken userToken) {
                    return userToken.getPrincipal() != null && userToken.isAuthenticated();
                } else {
                    return false;
                }
            }
    
            public boolean isHuaWeiLogin() {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication != null && authentication instanceof HuaWeiUserAuthenticationToken userToken) {
                    return userToken.getPrincipal() != null && userToken.isAuthenticated();
                } else {
                    return false;
                }
            }
    
            public boolean isAppleLoginAndHasPermissions(String ...permission) {
                if(!isAppleLogin()){
                    return false;
                }
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                //todo xxxx
                return false;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
  • 相关阅读:
    双目立体匹配_StereoNet网络配置训练过程中遇到的问题
    Android MediaCodec 简明教程(九):使用 MediaCodec 解码到纹理,使用 OpenGL ES 进行处理,并编码为 MP4 文件
    2-12.基金国际化的发展概况
    c++vector容器
    Tomcat catalina.properties配置文件详解
    2. 一步步搭建多层神经网络及应用
    第十四届蓝桥杯python第二期模拟赛
    Css Flex 弹性布局中的换行与溢出处理方法
    人大金仓分析型数据库最大量限制
    创建一个react项目 create-next-app
  • 原文地址:https://blog.csdn.net/it_freshman/article/details/132723065