DisabledEncodeUrlFilter:阻止将sessionId写到url中,防止由于http请求的访问日志导致Session泄露。
❝❞
先使用装饰者模式,通过继承HttpServletResponseWrapper将response包装起来,然后将包装后的对象作为response走过滤器链的下面过程 继承的目的是重写response相关的encodeUrl相关的方法,原样返回url(取消将sessionId写到url)
❝Spring Web中有一个WebAsyncManager可允许我们的请求是异步执行的,如果请求是异步处理请求肯定会启动一个新的线程。如果想要在异步的线程中获取SecurityContext肯定是不行的。因为默认的SpringContextHodler持有的SecurityContextHolderStrategy是基于ThreadLocal的。
❞
❝通过提前使用springmvc的WebAsyncUtils获取WebAsyncManager,来往里面注册SecurityContextCallableProcessingInterceptor拦截器,这个拦截器会在异步线程池提交任务前从SecurityContextHolder中获取SecurityContext,在callable任务执行call方法前,将提前获取的SecurityContext设置到当前线程中,保证在异步请求中也能拿到SecurityContext
❞
protected void WebAsyncManagerIntegrationFilter#doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 在执行异步之前会执行一堆的拦截器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager
.getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY);
if (securityProcessingInterceptor == null) {
// 向WebAsyncManager注册SecurityContextCallableProcessingInterceptor拦截器
asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY,
new SecurityContextCallableProcessingInterceptor());
}
filterChain.doFilter(request, response);
}
SecurityContextCallableProcessingInterceptor:在异步方法执行前,将当前持有的securityContext放到异步线程中
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
SecurityContextHolder.setContext(this.securityContext);
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
SecurityContextHolder.clearContext();
}
HeaderWriterFilter:写响应头,通过委托把将写响应头的工作交给维护的一堆HeaderWraiter去实现
CsrfFilter:防止跨站请求伪造
❝❞
默认只处理非"GET", "HEAD", "TRACE", "OPTIONS"的请求 里面使用CsrfTokenRepository保存csrfToken,默认实现是HttpSessionCsrfTokenRepository,将csrfToken存入HttpSession中 从请求头或者请求参数中获取到的csrfToken值与保存的csrfToken值必须相同,才会放行到下一个过滤器,来防止跨站请求伪造(就算拿了JESESSIONID,没有csrf的请求参数(_csrf)或头(X-XSRF-TOKEN)与后端不一致,也请求不了)
LogoutFilter
❝❞
默认处理退出登录的路径是/logout(可以自定义),退出登录的具体逻辑委托给自身的LogoutHandler处理器(组合模式,可组合多个退出登录的处理器,比如销毁会话、清空SecurityContext、发布退出成功事件),退出成功后,由logoutSuccessHandler处理,然后直接return停止过滤器的执行。
RequestCacheAwareFilter
❝❞
用户未经过认证访问某个url时,保存此请求对象,默认通过保存到HttpSession实现。 而当用户登录成功后,将之前保存的请求对象放入过滤器链中执行
SecurityContextHolderAwareRequestFilter
❝❞
通过HttpServletRequestFactory将HttpServletRequest请求包装成SecurityContextHolderAwareRequestWrapper,实现了getUserPrincipal()、getRemoteUser()等,这些方法会直接从SecurityContext获取认证对象中的用户信息,这样就可以直接调用request#getUserPrincipal()获取对应的用户信息。
AnonymousAuthenticationFilter
❝❞
当SecurityContex中没有Authentication时,会创建出一个AnonymousAuthenticationToken的Authentication对象(principals属性默认为"anonymousUser",authorities属性默认为"ROLE_ANONYMOUS") SpringSecurity中将用户分为登录的和未登录的,未登录的就是匿名用户,登录的又分为认证的(可能通过rememberMe的方式登录)和完全认证的(通过UsernamePassword完全登录)
ExceptionTranslationFilter
❝❞
位于FilterSecurityInterceptor过滤器之前,对后面filterChain.doFilter(..)进行了try-catch,并使用throwableAnalyzer分析抛出的异常,对security中的2种异常:AuthenticationException(认证异常,一般重定向到认证入口)、AccessDeniedException(访问拒绝-未完全认证或权限不够)做处理
欢迎加入 DevXTalk 的技术交流群,在这里你可以和大佬们一起交流分享技术,行业经验,提升自我。
结识新的业内朋友,扩大自己的圈子,当你想换工作的时候也许就能拿到不错的 offer 。总之期待你的加入...
「看完本文有收获?转发给更多的朋友吧」
「DevXTalk 不止于技术」
原文作者:DevXTalk;如有侵权,请联系管理员删除。