当前位置: 首页 > 科技观察

SpringSecurity权限控制系列(四)

时间:2023-03-12 06:17:36 科技观察

环境:Springboot2.4.12+SpringSecurity5.4.9本文主要内容:核心过滤器创建原理自定义过滤器上一篇:《??Spring Security权限控制系列(三)??》核心过滤器创建原理SpringSecurity核心在于通过Filter过滤链完成一系列逻辑处理,如CSRF、认证、授权验证、Session管理等功能。这些过滤器被封装在DefaultSecurityFilterChain中,最终的过滤器链会被添加到实际过滤器中的FilterChainProxy(过滤器的Bean名称为springSecurityFilterChain)中。回顾过滤器FilterChainProxy和过滤器链的创建过程DefaultSecurityFilterChain:FilterChainProxycreation//1.创建FilterChainProxy进程publicclassWebSecurityConfiguration{@Bean(name=AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)publicFilterspringSecurityFilterChain当前环境(是否有)自定义安全配置器类(WebSecurityConfigurerAdapter);这是自动注入的布尔值h??asConfigurers=this.webSecurityConfigurers!=null&&!this.webSecurityConfigurers.isEmpty();//当前环境是否有自定义的SecurityFilterChain过滤链Bean(这里是自动注入)booleanhasFilterChain=!this.securityFilterChains.isEmpty();//如果当前环境存在以上两种情况,则抛出异常。只能成立一个。Assert.state(!(hasConfigurers&&hasFilterChain),"找到WebSecurityConfigurerAdapter以及SecurityFilterChain。请只选择一个。");//如果不存在,将创建一个默认的SecurityConfigurer//当我们只在我们的项目中引入SpringSecurity包时就是这种情况){});this.webSecurity.apply(适配器);}//...//判断当前环境是否有自定义WebSecurityCustomizer类型的bean//我们可以自定义WebSecurityCustomizer,设置WebSecurity忽略的请求URIfor(WebSecurityCustomizercustomizer:this.webSecurityCustomizers){customizer.customize(this.webSecurity);}//通过WebSecurity构建FilterChainProxy#build方法returnthis.webSecurity.build();}}WebSecurity#build构建FilterChainProxy过滤器。publicfinalclassWebSecurity{privatefinalListignoredRequests=newArrayList<>();protectedFilterperformBuild()throwsException{//计算过滤器链的大小,这两组怎么设置?//ignoredRequests可以通过自定义WebSecurityCustomizer添加//通过web.ignoring().antMatchers("/demos/home");method//securityFilterChainBuilders是通过我们自定义的WebSecurityConfigurerAdapter#initHttpSecurityintchainSize=this.ignoredRequests.size()+this.securityFilterChainBuilders.size();ListsecurityFilterChains=newArrayList<>(chainSize);//为每个被忽略的uri配置一个过滤器链(注意:这个过滤器链中的过滤器链是Nofilter)}//securityFilterChainBuilders上面已经说了,基本上就是我们自定义的WebSecurityConfigurerAdapter//而这个类在执行build方法其实就是为HttpSecurity构建一个过滤链for(SecurityBuildersecurityFilterChainBuilder:this.securityFilterChainBuilders){securityFilterChains.add(securityFilterChainBuilder.build());}FilterChainProxyfilterChainProxy=newFilterChainProxy(securityFilterChains);//执行Bean的初始化过程filterChainProxy.afterPropertiesSet();过滤结果=filterChainProxy;返回结果;}}以上就是创建核心过滤器FilterChainProxy的底层实现原理。DefaultSecurityFilterChain创建过滤器链的创建。其实上面已经提到了它是如何创建的。主要有三种方式:自定义SecurityFilterChain类型的Bean使用该方式,我们可以不自定义WebSecurityConfigurerAdapter。@ComponentpublicclassCustomSecurityFilterChain实现SecurityFilterChain{@Overridepublicbooleanmatches(HttpServletRequestrequest){returnfalse;}@OverridepublicListgetFilters(){returnnewArrayList<>()CompusCubanCubanTypeofcustomWebSecurityclassCustomWebSecurityimplementsWebSecurityCustomizer{@Overridepublicvoidcustomize(WebSecurityweb){web.ignoring().antMatchers("/demos/家”);}}这种方式是为每个定义的URI链创建一个没有过滤器的过滤器。CustomWebSecurityConfigurerAdaptertypeBean@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{//...}这个方法在上面的源码展示中已经看到,上面的代码片段。对于(securityBuilder<?扩展了安全性filterchain>securityFilterChainBuilder:this.securityfilterchainbuilders){//httpseceRity#构建filterfilterfilterfilter构建securityFilterFilterChains.Add(securityFilterChainBuilderElter.build.build.build.builderecurerters;}自自中间。publicabstractclassWebSecurityConfigurerAdapter{publicvoidinit(WebSecurityweb)throwsException{//构建HttpSecurity对象HttpSecurityhttp=getHttp();web.addSecurityFilterChainBuilder(http).postBuildAction(()->{FilterSecurityInterceptorsecurityInterceptor=http.getSharedObject(FilterSecurityInterceptor.class);web.securityInterceptor(securityInterceptor);});}}HttpSecurity构建过滤器链。publicfinalclassHttpSecurity{protectedDefaultSecurityFilterChainperformBuild(){this.filters.sort(OrderComparator.INSTANCE);ListsortedFilters=newArrayList<>(this.filters.size());for(Filterfilter:this.filters){sortedFilters.add(((OrderedFilter)filter).filter);}返回新的DefaultSecurityFilterChain(this.requestMatcher,sortedFilters);}}到这里应该就很清楚了,底层创建核心过滤器FilterChainProxy以及过滤器和SecurityFilterChain过滤器链的创建关系和过滤器链有几种方式。过滤器链中的每个过滤器均由系统提供。每个过滤器处理不同的方面。如果我们想将我们的一些处理过滤器添加到现有的过滤器链中怎么办?操作?SpringSecurity为我们提供了向过滤器链中添加过滤器的接口。接下来,我们将通过示例来了解如何将我们自定义的过滤器添加到过滤器链中,以实现我们自己的逻辑。自定义过滤器@ComponentpublicclassAutoAuthenticationFilterextendsOncePerRequestFilter{@ResourceprivateAuthenticationManagerauthenticationManager;@OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{UsernamePasswordAuthenticationTokenauthenication=newUsernamePasswordAuthenticationToken("admin","123123");authenication.setDetails(newWebAuthenticationDetailsS??ource().buildDetails(request));身份验证auth=authenticationManager.authenticate(authenication);if(auth!=null){SecurityContextHolder.getContext().setAuthentication(auth);request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,SecurityContextHolder.getContext());}System.out.println("------------------------自动身份验证过滤器...");filterChain.doFilter(请求,响应);}}添加到过滤器链注册以下4个方法通过自定义WebSecurityConfigurerAdapter#configure(HttpSecurityhttp)添加过滤器来注册自定义过滤器。@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@ResourceprivateAutoAuthenticationFilterauthFilter;protectedvoidconfigure(HttpSecurityhttp)throwsException{//将自定义的过滤器添加到UsernamePasswordAuthenticationFilter通过过滤器的前面http.addFilterBefore(authFilter,UsernamePasswordAuthenticationFilter.class);}}总结:filter创建的实现原理。自定义过滤器的应用。