SpringSecurity源码学习(六)

本文深入探讨SpringSecurity的HttpSecurity构建器中的配置器,详细解析每个配置器如CsrfConfigurer、ExceptionHandlingConfigurer等如何初始化和配置过滤器。文章还介绍了SecurityContextPersistenceFilter、CsrfFilter、LogoutFilter等过滤器的工作原理,阐述了它们在安全链中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本文讨论HttpSecurity这个构建器中的配置器在HttpSecurity构建SecurityChainFilter的过程中做的事情。

HttpSecurity中配置器

比如在我写的例子中,HttpSecurity中有11个配置器。那么会顺序调度这11个配置器的init()、configurer()。
这里写图片描述

这里要强调的是,不是一个配置器对应一个过滤器。另外,配置的器的调度顺序和其生成的过滤器顺序无关,SecurityChainFilter过滤链中的过滤器顺序是由FilterComparator这个比较器决定的。

CsrfConfigurer

添加的过滤器
CsrfFilter

ExceptionHandlingConfigurer

添加的过滤器
ExceptionTranslationFilter

HeadersConfigurer

添加响应头。默认添加的结果是:

   Cache-Control: no-cache, no-store, max-age=0, must-revalidate
   Pragma: no-cache
   Expires: 0
   X-Content-Type-Options: nosniff
   Strict-Transport-Security: max-age=31536000 ; includeSubDomains
   X-Frame-Options: DENY
   X-XSS-Protection: 1; mode=block

SessionManagementConfigurer

添加的过滤器
SessionManagementFilter
ConcurrentSessionFilter

SecurityContextPersistenceFilter

添加的过滤器
SecurityContextPersistenceFilter

AnonymousConfigurer

添加的过滤器
AnonymousAuthenticationFilter

ServletApiConfigurer

添加的过滤器
SecurityContextHolderAwareRequestFilter

DefaultLoginPageConfigurer

添加的过滤器
DefaultLoginPageGeneratingFilter

LogoutConfigurer

添加的过滤器
LogoutFilter

FormLoginConfigurer

添加的过滤器
UsernamePasswordAuthenticationFilter


过滤器


这里写图片描述

除了我自定义的验证码过滤器(CustomCapchaFilter),其他的过滤器都是系统生成的。

SecurityContextPersistenceFilter

SecurityContextHolder是和当前线程关联的SecurityContext存放容器,SecurityContextRepository是和当前session关联的SecurityContext存放容器。
这个过滤器做的事情就是,使用SecurityContextRepository中获取的SecurityContext(不会返回null,如果不存在,会返回一个SecurityContext,这里面是一个空的Authtication)填充SecurityContextHolder。这样,在线程处理请求的任何一个地方,都可以通过它来获取、设置SecurityContext(特别是在我们的controller中,可以直接使用它获取当前用户)。当请求处理完成之后(经过了后续过滤链、controller、service等的处理),将SecurityContextHolder的数据保存到SecurityContextRepository中,清空SecurityContextHolder。

CsrfFilter

这个过滤器就是添加csrf的功能。
使用LazyCsrfTokenRepository包裹的HttpSessionCsrfTokenRepository将生成的CsrfToken存放在HttpSession中。当请求来的时候,判断session中有无CsrfToken,没有就生成一个,然后保存到session中。并且将生成的CsrfToken放在request对象中,默认key是“_csrf”。然后判断请求需不需要csrf校验,如果不需要则调下一个过滤器。如果需要,则判断用户的请求中请求头或请求体中的csrf与session中的时候相同,相同则校验通过。否则,调用accessDeniedHandler处理。

LogoutFilter

提供登出的功能。
判断请求是不是登出请求,如果是,迭代配置的所有LogoutHandler(比如在CsrfConfigurer中配置csrf过滤器时,给此过滤器的配置器添加了一个CsrfLogoutHandler,用于在登出的时候,清空csrfToken).
最后再调用logoutSuccessHandler。

UsernamePasswordAuthenticationFilter

登录认证(密码校验)。
严格来说,它并不是一个认证过滤器,它的父类AbstractAuthenticationProcessingFilter才是。判断请求是否是登录认证请求,如果是,则进行密码校验。具体进行验证的是AuthticationManager。认证成功之后将返回一个fully的Authtication对象。注意,认证成功之后,将执行sessionStrategy,默认是修改sessionId,预防session fixation攻击。并且在认证成功之后,是不继续走过滤链的,直接将请求交给successHandler处理了。

RequestCacheAwareFilter

判断当前请求对应的session中,有无key=SPRING_SECURITY_SAVED_REQUEST的对象,有则表示有保存的request对象,那么就使用保存的这个对象重新请求。

SecurityContextHolderAwareRequestFilter

拓展了httpServletRequest的功能。

HttpServletRequest.authenticate(HttpServletResponse)
HttpServletRequest.login(String, String) 
HttpServletRequest.logout()
AsyncContext.start(Runnable) 

AnonymousAuthenticationFilter

判断SecurityContextHolder中Authentication是否是null,如果是,则创建AnonymousAuthenticationToken。

SessionManagementConfigurer

不理解

ExceptionTranslationFilter

这个过滤器架起了java异常到Http response的桥梁。
如果遇到 AuthenticationException,交给authenticationEntryPoint处理
如果遇到 AccessDeniedException ,交给AccessDeniedHandler处理

FilterSecurityInterceptor

虽然这个类名字不是XXFilter,但他确实是一个过滤器。它不是由前面XXX配置器创建的。而是由AbstractInterceptUrlConfigurer创建的。它是整个权限校验的入口,另开一章吧。。。

@Override
    public void configure(H http) throws Exception {
        FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
        if (metadataSource == null) {
            return;
        }
        FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
                http, metadataSource, http.getSharedObject(AuthenticationManager.class));
        if (filterSecurityInterceptorOncePerRequest != null) {
            securityInterceptor
                    .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
        }
        securityInterceptor = postProcess(securityInterceptor);
        http.addFilter(securityInterceptor);
        http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值