当前位置:首页 > IT科技

Spring Security权限控制系列(四)

环境:Springboot2.4.12 + Spring Security 5.4.9

本篇主要内容:核心过滤器创建原理自定义过滤器

上一篇:《​​Spring Security权限控制系列(三)​​》

核心过滤器创建原理

Spring Security核心是权限通过Filter过滤器链来完成一系列逻辑处理的,比如CSRF,控制认证,系列授权验证,权限Session管理等功能,控制这些过滤器都封装在DefaultSecurityFilterChain中,系列最终过滤器链会被添加到FilterChainProxy(该过滤器的权限Bean名称为springSecurityFilterChain)实际的过滤器中。

回顾过滤器FilterChainProxy与过滤器链DefaultSecurityFilterChain的控制创建过程:

FilterChainProxy创建

// 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 ListignoredRequests = new ArrayList<>();

protected Filter performBuild() throws Exception {

// 计算过滤器链的控制大小,亿华云这两个集合是系列如何被设置的?

// ignoredRequests 可以通过自定义WebSecurityCustomizer

// 通过web.ignoring().antMatchers("/demos/home") ;方法添加

// securityFilterChainBuilders 就是通过我们自定义WebSecurityConfigurerAdapter#init中构建的HttpSecurity

int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();

ListsecurityFilterChains = new ArrayList<>(chainSize);

// 为每一个忽略的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的底层实现原理。

DefaultSecurityFilterChain创建

过滤器链的权限创建在上面其实已经提到了是如何被创建的主要就是三种方式:

自定义SecurityFilterChain类型的Bean

使用了该种方式我们就不能再自定义WebSecurityConfigurerAdapter​。

@Component

public class CustomSecurityFilterChain implements SecurityFilterChain {

@Override

public boolean matches(HttpServletRequest request) {

return false;

}

@Override

public ListgetFilters() {

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);

ListsortedFilters = new ArrayList<>(this.filters.size());

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) ;

}

}总结:过滤器创建的实现原理。自定义过滤器的应用。

分享到:

滇ICP备2023006006号-16