环境:Springboot2.4.12 + Spring Security 5.4.9 上一篇:《Spring Security权限控制系列(三)》 Spring Security核心是权限通过Filter过滤器链来完成一系列逻辑处理的,比如CSRF,控制认证,系列授权验证,权限Session管理等功能,控制这些过滤器都封装在DefaultSecurityFilterChain中,系列最终过滤器链会被添加到FilterChainProxy(该过滤器的权限Bean名称为springSecurityFilterChain)实际的过滤器中。 回顾过滤器FilterChainProxy与过滤器链DefaultSecurityFilterChain的控制创建过程: // 1.创建FilterChainProxy过程 public class WebSecurityConfiguration { @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { // 当前环境中是否有自定义SecurityConfigurer类(WebSecurityConfigurerAdapter);这里是自动注入的 boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty(); // 当前环境中是否有自定义的SecurityFilterChain过滤器链Bean(这里是自动注入的) boolean hasFilterChain = !this.securityFilterChains.isEmpty(); // 如果当前环境上面的两种情况都存在则会抛出异常。只能有一个成立即可 Assert.state(!(hasConfigurers && hasFilterChain),系列 "Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one."); // 如果都不存在,则会创建一个默认的权限SecurityConfigurer // 当我们项目中只是引入Spring Security包时就是该中情况 if (!hasConfigurers && !hasFilterChain) { WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() { }); this.webSecurity.apply(adapter); } // ... // 查找当前环境中是否有自定义的WebSecurityCustomizer类型的Bean // 我们可以自定义WebSecurityCustomizer然后设置WebSecurity忽略的请求URI for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) { customizer.customize(this.webSecurity); } // 通过WebSecurity#build方法来构建FilterChainProxy return this.webSecurity.build(); } WebSecurity#build构建FilterChainProxy过滤器。 public final class WebSecurity { private final List protected Filter performBuild() throws Exception { // 计算过滤器链的控制大小,亿华云这两个集合是系列如何被设置的? // ignoredRequests 可以通过自定义WebSecurityCustomizer // 通过web.ignoring().antMatchers("/demos/home") ;方法添加 // securityFilterChainBuilders 就是通过我们自定义WebSecurityConfigurerAdapter#init中构建的HttpSecurity int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size(); List // 为每一个忽略的uri配置一个过滤器链(注意:该中过滤器链中是没有过滤器的) for (RequestMatcher ignoredRequest : this.ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } // securityFilterChainBuilders上面已经说过基本就是我们自定义的WebSecurityConfigurerAdapter // 而该类在执行build方法的时候其实就是为HttpSecurity构建过滤器链 for (SecurityBuilder securityFilterChainBuilder : this.securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); // 执行Bean的初始化过程 filterChainProxy.afterPropertiesSet(); Filter result = filterChainProxy; return result; } 以上就是创建核心过滤器FilterChainProxy的底层实现原理。 过滤器链的权限创建在上面其实已经提到了是如何被创建的主要就是三种方式: 使用了该种方式我们就不能再自定义WebSecurityConfigurerAdapter。 @Component public class CustomSecurityFilterChain implements SecurityFilterChain { @Override public boolean matches(HttpServletRequest request) { return false; } @Override public List return new ArrayList<>() ; } }自定义WebSecurityCustomizer类型的控制Bean@Component public class CustomWebSecurity implements WebSecurityCustomizer { @Override public void customize(WebSecurity web) { web.ignoring().antMatchers("/demos/home") ; } 这种方式就是为每一个定义的URI创建一个没有过滤器的过滤器链。 自定义WebSecurityConfigurerAdapter类型的系列Bean@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... 该种方式在上面的源码展示中已经看到了,上面的代码片段。源码下载 for (SecurityBuilder securityFilterChainBuilder : this.securityFilterChainBuilders) { // HttpSecurity#build构建Filter过滤器练 securityFilterChains.add(securityFilterChainBuilder.build()); 自定义WebSecurityConfigurerAdapter子类将HttpSecurity添加到WebSecurity.securityFilterChainBuilders集合中。 public abstract class WebSecurityConfigurerAdapter { public void init(WebSecurity web) throws Exception { // 构建HttpSecurity对象 HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(() -> { FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class); web.securityInterceptor(securityInterceptor); }); } HttpSecurity构建过滤器链。 public final class HttpSecurity { protected DefaultSecurityFilterChain performBuild() { this.filters.sort(OrderComparator.INSTANCE); List for (Filter filter : this.filters) { sortedFilters.add(((OrderedFilter) filter).filter); } return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters); } 到此应该非常清楚底层创建核心过滤器FilterChainProxy及该过滤器与SecurityFilterChain过滤器链的关系及过滤器链创建的几种方式。 过滤器链中的每一个过滤器都是有系统提供的,每种过滤器都处理不同方面的事,如果我们希望在现有的过滤器链中加入我们的一些处理过滤该如何操作?Spring Security为我们提供了往过滤器链中添加过滤器的接口,接下来通过实例来看如何向过滤器链中添加我们自定义的过滤器,以此实现我们自己的逻辑。 @Component public class AutoAuthenticationFilter extends OncePerRequestFilter { @Resource private AuthenticationManager authenticationManager ; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { UsernamePasswordAuthenticationToken authenication = new UsernamePasswordAuthenticationToken("admin", "123123") ; authenication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)) ; Authentication auth = authenticationManager.authenticate(authenication) ; if (auth != null) { SecurityContextHolder.getContext().setAuthentication(auth) ; request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()) ; } System.out.println("--------------------------Auto Authenticaton Filter...") ; filterChain.doFilter(request, response) ; } 通过自定义的WebSecurityConfigurerAdapter#configure(HttpSecurity http)注册自定义的过滤器。下面4个方法来添加过滤器。 @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private AutoAuthenticationFilter authFilter; protected void configure(HttpSecurity http) throws Exception { // 将自定义的过滤器添加到UsernamePasswordAuthenticationFilter过滤器的前面 http.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class) ; }核心过滤器创建原理
自定义过滤器