首页>>后端>>Spring->SpringSecurity原理分析

SpringSecurity原理分析

时间:2023-11-30 本站 点击:0

本文我们主要梳理下SpringSecurity的原理,SpringSecurity主要是用于认证、授权的,其的主要原理就是通过Filter来处理。

一、SpringSecurity的基本原理

1、基本流程

SpringSecurity的基本原理就是应用了Tomcat容器的Filter,其的实现原理也就是类似于Tomcat本身的ApplicationFilterChain,也就是Filter执行链。

publicfinalclassApplicationFilterChainimplementsFilterChain{........privateApplicationFilterConfig[]filters=newApplicationFilterConfig[0];...........publicApplicationFilterChain(){}publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{..........}else{this.internalDoFilter(request,response);}}privatevoidinternalDoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.pos<this.n){ApplicationFilterConfigfilterConfig=this.filters[this.pos++];try{Filterfilter=filterConfig.getFilter();.........}else{filter.doFilter(request,response,this);}.........}else{try{.........}else{this.servlet.service(request,response);}}........}}}

ApplicationFilterChain本身就是先执行所有的filters,执行完成后,其就会执行当前请求的Servlet,对于SpringMVC来说,就是DispatchSevelt

这里也就是说,先执行Tomcat自身已有的Filter,然后再交给SpringSecurity定义的FilterChainProxy,然后其再去执行SpringSecurity用于认证、授权管理的各种Filter。这个就是SpringSecurity的核心原理。

2、默认注入的Filter列表

我们看下默认引入spring-boot-starter-security后其会默认加入的Filter

3、FilterChainProxy

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}

二、SpringSecurity对FilterChain的组装初始化

其的组装是借助于两个类来添加关于认证、授权相关的信息,由这些信息来添加FilterChain中需要的Filter,这两个类就是WebSecurityHttpSecurity

1、WebSecurity、HttpSecurity

这两个类都是继承的AbstractConfiguredSecurityBuilder,以及实现SecurityBuilder接口(用于构建对象)。

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}

2、AbstractConfiguredSecurityBuilder

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();

这个基类主要有两个成员变量需要关注,也就是configurers,与sharedObjectsconfigurers(SecurityConfigurer)这个主要是添加的各种配置信息。然后sharedObjects中是添加一些共享的类对象,然后需要就能取出来。例如:

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}

而对于SecurityConfigurer的添加主要是使用apply()方法:

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}

3、SecurityConfigurer

publicinterfaceSecurityConfigurer<O,BextendsSecurityBuilder<O>>{voidinit(Bbuilder)throwsException;voidconfigure(Bbuilder)throwsException;}

其主要是两个方法,一个就是先init产生化,另一个就是configure,也就是通过configure方法来设置SecurityBuilder中的内容。

下面我们来看下WebSecurity的构建,以及通过其来产生FilterChainProxy

@Autowired(required=false)publicvoidsetFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object>objectPostProcessor,@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")List<SecurityConfigurer<Filter,WebSecurity>>webSecurityConfigurers)throwsException{this.webSecurity=objectPostProcessor.postProcess(newWebSecurity(objectPostProcessor));if(this.debugEnabled!=null){this.webSecurity.debug(this.debugEnabled);}..........for(SecurityConfigurer<Filter,WebSecurity>webSecurityConfigurer:webSecurityConfigurers){this.webSecurity.apply(webSecurityConfigurer);}this.webSecurityConfigurers=webSecurityConfigurers;}

这里我们看到入参有webSecurityConfigurers(List<SecurityConfigurer),而我们当前有添加一个WebSecurityConfigurerAdapter, 其是继承与WebSecurityConfigurerAdapter,可以看到其是属于SecurityConfigurer,我们能通过其来进行对应的属性拓展

然后就是通过this.webSecurity.apply(webSecurityConfigurer)来添加到configurers

4、构建Filter(FilterChainProxy)

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}0

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}1

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}2

这里的init(),就是遍历configurers进行初始化:

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}3

再通过configure()遍历执行configurersconfigurer方法:

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}4

例如我们当前添加了自定义的SecurityConfiguration

这里还有beforeConfigure()方法,例如HttpSecurity对其的实现:

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}5

添加认证管理器。对于SecurityConfigurer的实现类来说,其主要是设置填充各种类对象例如我们当前填充了`UserDetailsService,以及属于SpringSecurityFilter

5、HttpSecurity构建

对于HttpSecurity的构建,其是在WebSecurity下构建的:

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}6

我们看到其是在前面doBuild()遍历调用init调用的。创建后,通过web.addSecurityFilterChainBuilder(http)添加到WebSecurity中。而定义对于HttpSecurity,其主要会通过SecurityConfigurer来添加各种Filter

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{privatefinalRequestMatcherConfigurerrequestMatcherConfigurer;privateList<OrderedFilter>filters=newArrayList<>();privateRequestMatcherrequestMatcher=AnyRequestMatcher.INSTANCE;privateFilterOrderRegistrationfilterOrders=newFilterOrderRegistration();

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}8

这里主要有三部:

1)、创建AuthenticationManager

publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}9

2)、再构建HttpSecurity

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{0

3)、填充HttpSecurity的配置内容。

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{1

我们下面再具体梳理这个过程。

6、AuthenticationManager

1)、AuthenticationManager认证管理器

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{2

其首先会调用configure(AuthenticationManagerBuilder)

2)、AuthenticationManagerBuilder设置授权管理器的内容

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{3

这里你可以添加自己的AuthenticationProviderUserDetailsService,或使用自带的内存UserDetailsServiceinMemoryAuthentication(),其是通过SecurityConfigurer来添加HttpSecurity的属性。

例如我们当前的WebSecurityConfigurerAdapter

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{4

其就设置UserDetailsService为我们自定义的。然后这里通过configure(AuthenticationManagerBuilder)拓展好AuthenticationManagerBuilder的一些属性后,下面就能通过来创建了。

3)、构建AuthenticationManager

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{5

这个build()同样是父类AbstractSecurityBuilder的方法:

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{6

其也是这一串逻辑:

这个也主要是SecurityConfigurer的方法调用,然后其的performBuild()方法

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{7

这里就讲其的authenticationProviders设置到ProviderManager, 也就是ProviderManager认证管理器,通过其的AuthenticationProvider也就是认证提供者来处理认证内容:

4)、ProviderManager认证处理管理器

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{8

我们看到这里是通过AuthenticationProvider来处理产生Authentication,也就是认证信息。

而对于这里的AuthenticationProvider,一般是怎样添加的呢?对于AuthenticationManagerBuilder,当我们设置UserDetailsService的时候,其就会添加DaoAuthenticationConfigurer

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{9

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{0

其就会产生一个DaoAuthenticationProvider,同时在configure(B builder)方法的时候,就会将DaoAuthenticationProvider设置到ProviderManagerBuilder中。

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{1

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{2

这里首先是通过retrieveUser方法使用UserDetailsService来查询到对应的用户,如果查询不到就抛出UsernameNotFoundException,如果能查询到,就再来解析认证判断,例如用户是否被锁定,密码是否匹配等,如果失败,就抛出AuthenticationException认证失败。

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{3

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{4

而对于AuthenticationException,也就是认证失败,我们看到这个异常是在接口控制的,所以一定要处理。

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{5

拿我们常见的UsernamePasswordAuthenticationFilter,也就是账密登录的Filter

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{6

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{7

其认证失败后就会通过AuthenticationException异常,来调用unsuccessfulAuthentication处理认证失败的情况。

其就是通过failureHandler来跳到/login?error页面

然后对于UsernamePasswordAuthenticationFilter来说,其后面就是DefaultLoginPageGeneratingFilter

其通过url,就会构建登录页面,然后直接就return了,就不会通过chain.doFilter(request, response)到下面的其他Filter以及Servlet了。

publicfinalclassHttpSecurityextendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity>implementsSecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity>{8

5)、对于认证的流程

7、applyDefaultConfiguration(this.http)默认设置

我们接走上面的创建HttpSecurity的步骤,来看下HttpSecurity中的Filter是怎样添加的:

protectedfinalHttpSecuritygetHttp()throwsException{if(this.http!=null){returnthis.http;}AuthenticationEventPublishereventPublisher=getAuthenticationEventPublisher();this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);publicclassFilterChainProxyextendsGenericFilterBean{..........privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{......List<Filter>filters=getFilters(firewallRequest);........VirtualFilterChainvirtualFilterChain=newVirtualFilterChain(firewallRequest,chain,filters);virtualFilterChain.doFilter(firewallRequest,firewallResponse);}........privatestaticfinalclassVirtualFilterChainimplementsFilterChain{privatefinalFilterChainoriginalChain;privatefinalList<Filter>additionalFilters;..........@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException{if(this.currentPosition==this.size){if(logger.isDebugEnabled()){logger.debug(LogMessage.of(()->"Secured"+requestLine(this.firewalledRequest)));}//Deactivatepathstrippingasweexitthesecurityfilterchainthis.firewalledRequest.reset();this.originalChain.doFilter(request,response);return;}this.currentPosition++;FilternextFilter=this.additionalFilters.get(this.currentPosition-1);if(logger.isTraceEnabled()){logger.trace(LogMessage.format("Invoking%s(%d/%d)",nextFilter.getClass().getSimpleName(),this.currentPosition,this.size));}nextFilter.doFilter(request,response,this);}}9this.authenticationBuilder.parentAuthenticationManager(authenticationManager);Map<Class<?>,Object>sharedObjects=createSharedObjects();publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{0if(!this.disableDefaults){applyDefaultConfiguration(this.http);ClassLoaderclassLoader=this.context.getClassLoader();List<AbstractHttpConfigurer>defaultHttpConfigurers=SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class,classLoader);for(AbstractHttpConfigurerconfigurer:defaultHttpConfigurers){publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{1}}configure(this.http);returnthis.http;}

其首先会通过applyDefaultConfiguration(this.http)方法添加一些默认的Filter

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}0

这里的例如http.csrf()http.headers()这些方法,其内部一般是这种方式,也就是需要什么就对应的调用方法例如http.anonymous(),其就会添加SecurityConfigurer,再等待configure()方法的调用,来注入对应SecurityConfigurer.configure的内容

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}1

1)、AnonymousConfigurer

例如当前的AnonymousConfigurer

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}2

init方法就会创建一个AnonymousAuthenticationFilter匿名Filter,以及一个AnonymousAuthenticationProvider,匿名认证提供者。然后在configure方法就会将authenticationFilter添加到HttpSecurity中:

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}3

2)、LogoutConfigurer

然后对于applyDefaultConfigurationhttp.logout(),其添加的就是LogoutConfigurer

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}4

这个就构建添加了LogoutFilter

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}5

当然我们也可以自动拓展来设置我们自己的信息:

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}6

3)、FilterSecurityInterceptor

当然我们上面是认证相关的内容,但还有授权信息,例如我们自己的拓展授权信息:

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}7

例如http.authorizeRequests(),这个是授权具体的哪个请求资源,其添加的就是ExpressionUrlAuthorizationConfigurer,也就是表达式授权配置:

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}8

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}9

其就是通过这些信息来构建FilterSecurityInterceptor

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();0

FilterSecurityInterceptor其是放在整条Filter链的最后一个:

其的处理主要是beforeInvocation(filterInvocation)方法:

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();1

通过authenticateIfRequired来解析认证,如果有需要的话

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();2

可以看到其本身其也是调用的认证管理器:this.authenticationManager.authenticate(authentication)

认证成功后就是授权attemptAuthorization(object, attributes, authenticated),这个就是你自己配置的一些规则:

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();3

其实通过访问决策管理器处理this.accessDecisionManager.decide(authenticated, object, attributes),如果没有权限,就抛出AccessDeniedException。与这个FilterSecurityInterceptor相关的就是其前面的ExceptionTranslationFilter这个Filter是放在FilterSecurityInterceptor前面的,其是通过默认的applyDefaultConfiguration(HttpSecurity http) 添加的http.exceptionHandling()

4)、ExceptionTranslationFilter

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();4

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();5

它的处理主要是两个,一个是处理AuthenticationException认证失败,另一个是AccessDeniedException访问授权失败

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();6

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();7

通过这两个来处理response返回内容,如果是认证失败:

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();8

publicabstractclassAbstractConfiguredSecurityBuilder<O,BextendsSecurityBuilder<O>>extendsAbstractSecurityBuilder<O>{privatefinalLoglogger=LogFactory.getLog(getClass());privatefinalLinkedHashMap<Class<?extendsSecurityConfigurer<O,B>>,List<SecurityConfigurer<O,B>>>configurers=newLinkedHashMap<>();privatefinalList<SecurityConfigurer<O,B>>configurersAddedInInitializing=newArrayList<>();privatefinalMap<Class<?>,Object>sharedObjects=newHashMap<>();9

通过authenticationEntryPoint来处理,我们以其实现Http403ForbiddenEntryPoint为例:

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}0

其就是对response输出403,访问拒绝。

如果是授权失败,其有两种如果当前Authentication是匿名认证,就调用sendStartAuthentication,也就是与前面的handleAuthenticationException一样:

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}1

如果不是匿名,则是通过AccessDeniedHandler访问拒绝处理其来处理,例如AccessDeniedHandlerImpl

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}2

也就是如果没有设置指定的errorPage,就直接返回textHttpStatus.FORBIDDEN

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}3

如果有页面,就forword到errorPage

8、filter的顺序

同时我们前面只介绍了Filter的添加http.addFilter,当这里还有添加顺序:

publicinterfaceSecurityBuilder<O>{Obuild()throwsException;}3

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}5

我们在添加一个Filter的时候,还需要指定整个Filter的位置

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}6

当前Security自带添加是使用addFilter(Filter filter)方法,在添加时实现会在filterOrders获取其的顺序来添加,其的初始化是:

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}7

这里初始化的时候就已经定义好顺序了

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}8

三、SpringSecurity对FilterChain的组装构建

1、添加HttpSecurity到WebSecurity

privateMap<Class<?>,Object>createSharedObjects(){Map<Class<?>,Object>sharedObjects=newHashMap<>();sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());sharedObjects.put(UserDetailsService.class,userDetailsService());sharedObjects.put(ApplicationContext.class,this.context);sharedObjects.put(ContentNegotiationStrategy.class,this.contentNegotiationStrategy);sharedObjects.put(AuthenticationTrustResolver.class,this.trustResolver);returnsharedObjects;}9

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}0

HttpSecurity构建好后,就讲其添加到WebSecurity中,继续构建WebSecurity

publicfinalclassWebSecurityextendsAbstractConfiguredSecurityBuilder<Filter,WebSecurity>implementsSecurityBuilder<Filter>,ApplicationContextAware{6

2、performBuild完成FilterChainProxy创建

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}2

这里的处理我们可以看到FilterChainProxy创建会通过(securityFilterChains),我们前面添加的HttpSecurity

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}3

3、FilterChainProxy的拦截逻辑

这个逻辑前面贴过了

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}4

我们当前的是SecurityFilterChain是通过HttpSecurity构建的,通过doBuilder

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}5

也就是将HttpSecurity以及其的匹配器RequestMatcher来构建。

public<CextendsSecurityConfigurer<O,B>>Capply(Cconfigurer)throwsException{add(configurer);returnconfigurer;}6

这个匹配器都拦截。

由此就完成了FilterChain的组装。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/4488.html