后面通过三篇文章,从底层代码的角度剖析了 SpringSecurity 的初始化过程。
接下来咱们就要具体看一下,Spring Security 的平安过滤器初始化、拆卸好之后,到底是怎么工作的。
还是按图索骥
上面咱们简略从底层源码剖析一下,申请是怎么调用到 Spring Security 的平安过滤器的。
Spring Security 平安过滤器工作原理
后面文章曾经剖析过 DelegatinFilterProxy 调用到 FilterChainProxy 的源码,所以咱们明天间接从 FilterChainProxy 的 doFilter 办法开始:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (!clearContext) {doFilterInternal(request, response, chain);
return;
}
try {request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
catch (RequestRejectedException ex) {this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
}
finally {SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
间接看 doInternalFilter 办法。首先调用 getFilters 办法:
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);
List<Filter> filters = getFilters(firewallRequest);
// 省略局部源码
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
virtualFilterChain.doFilter(firewallRequest, firewallResponse);
}
这个 getFilters 办法的源码就不贴出了,有趣味的同学关上源码看一下,非常简单:从 FilterChainProxy 持有的 DefaultSecurityFilterChain 对象中获取到 filters,这个 filters 就是 Spring Security 初始化过程中拆卸好的 Spring Security 的各平安过滤器。
之后用平安过滤器组装一个叫 virtualFilterChain 的外部对象,这个外部对象次要就是为了持有 Spring Security 的平安过滤器的,而后通过调用 virtualFilterChain 的 doFilter 办法,一一调用 Spring Security 的平安过滤器。
Spring Security 平安过滤器
Spring Security 有不少平安过滤器(下图,SprigBoot 默认启动的就有 15 个),咱们次要关注与用户身份认证及鉴权密切相关的、或者我的项目中比拟常见的过滤器,其余过滤器临时略过或一笔带过。
1.WebAsyncManagerIntegrationFilter
web 异步集成过滤器,创立 SecurityContextCallableProcessingInterceptor 并注册到 WebAsyncManager 中。
具体作用略。
2.SecurityContextPersistenceFilter
将蕴含认证信息的 SecurityContextHolder 在认证之后保存起来(保留在 SecurityContextRepository 中,个别状况下是 session),并且在每次申请发动、认证产生之前从 SecurityContextRepository 获取进去搁置到 SecurityContextHolder 中。
SecurityContextPersistenceFilter 是 Spring Security 的第 2 个平安过滤器,在所有认证过滤器之前执行。
SecurityContextPersistenceFilter 首先从 session 中(默认状况下)获取 SecurityContext,如果 session 中没有 SecurityContext 则创立一个空的 SecurityContext,之后将 SecurityContext 存入 SecurityContextHolder。
默认状况下 SecurityContextHolder 通过 ThreadLocalSecurityContextHolderStrategy(也就是应用 ThreadLocal)存储 SecurityContext。
最初,在申请执行实现之后,将 SecurityContextHolder 持有的 SecurityContext 保存起来(默认存储在 session 中),并清空 SecurityContextHolder。
这样,通过 SecurityContextPersistenceFilter 过滤器,Spring Security 就能够在其余平安过滤器执行之前,从 session 中获取以后用户的认证信息,因此在后续用户认证操作执行之前、如果以后用户曾经实现了认证、则能够确保可能获取到以后用户的认证信息,因而可能通过后续的用户认证过程!!!
3.HeaderWirterFilter
写 Response 头信息以便达到对 Http Response 的相应管制。
HeaderWirterFilter 初始化的时候会注册如下 HeadWriter:
这些 HeadWriter 会帮忙咱们对 Http Response Header 做一些默认设置,比方 CacheControlHeadersWriter 会执行如下操作:
private static List<Header> createHeaders() {List<Header> headers = new ArrayList<>(3);
headers.add(new Header(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"));
headers.add(new Header(PRAGMA, "no-cache"));
headers.add(new Header(EXPIRES, "0"));
return headers;
}
个别状况下,咱们的利用须要这样的设置,不应用 Spring Security 的话咱们的利用须要手动设置,应用了 Spring Security 的话,就不须要多此一举了。
4.CsrfFilter
跨域申请过滤器,次要作用是防跨域攻打。
5.LogoutFilter
解决 Logout 申请,并导航到 logout 页面。
6.UsernamePasswordAuthenticationFilter
这是 Spring Security 用户认证的默认实现。
他有一个叫 AbstractAuthenticationProcessingFilter 的父类,doFilter 办法就是在父类实现的。
只针对 post 办法的 /login 申请失效,所以如果咱们要应用该过滤器的话,利用的登录必须是 post 办法的 /login 申请。
Spring Security 的登录认证过程就是通过这个过滤器实现的,绝对还比较复杂,篇幅关系明天就不开展了,明天的次要指标是要搞清楚他的作用。
首先验证以后申请是否须要登录认证,如前所述,如果申请不是 post 的 /login 的话,则不做登录认证。
从 request 中获取的 username,password 创立 UsernamePasswordAuthenticationToken 对象进行认证。
认证的过程其实就是咱们验证用户名、明码的过程,SpringSecurity 有一个默认的用户名、明码认证实现,是在系统启动过程中为用户 user 生成 UUID 并打印在控制台、通过用户名 user、明码为该 UUID 实现认证。咱们能够实现本人的认证,比方通过数据库的用户名、明码形式实现认证。
认证通过则将认证信息存储在 SecurityContext 中,如果认证失败(比方用户名明码谬误等)则清空 SecurityContext 并记录相干异样。
7.DefaultLoginPageGeneratingFilter
为 /login 申请生成登录页面。
8.DefaultLogoutPageGeneratingFilter
导航到登出页面。
9.BasicAuthenticationFilter
对于采纳 Basic Authentication 的申请执行认证。Basi Authentication 指的是申请头中蕴含:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
其中 Basic 后是采纳 base64 编码的明码信息。
不太理解、没有应用过这种认证形式,略过。
10.RequestCacheAwareFilter
次要作用是缓存以后申请信息,以便在因为认证未通过无奈执行该申请的状况下,后续认证通过后从新发动该申请。
11.SecurityContextHolderAwareRequestFilter
用于对 request 做一层包装,以便反对 Servlet 中平安相干的 API 调用。
12.AnonymousAuthenticationFilter
匿名过滤器,从 SecurityContextHolder 获取认证信息,如果通过了后面的 SecurityContextPersistenceFilter、以及 UsernamePasswordAuthenticationFilter 解决后,SecurityContextHolder 中还是没有认证信息的话,阐明以后申请并没有通过 Spring Security 的平安认证,则创立一个匿名认证信息存储在 SecurityContextHolder 中。
13.SessionManagementFilter
session 治理的过滤器,次要为了避免 session 固化攻打、以及实现登录并发管制性能。
14.ExceptionTranslationFilter
实现异样管制的平安过滤器,留神该过滤器对异样的解决是平安过滤器链执行实现、返回之后。所以,上面的第 14 个、第 15 个过滤器执行过程中的异样,也能被本过滤器捕捉并解决。
次要解决 Spring Security 的两类异样:
- AuthenticationException
- AccessDeniedException
并将异样交给相应的异样处理器进行解决,比方 AccessDeniedException 异样处理器通常会通过 response 返回前端 403 谬误。
15.FilterSecurityInterceptor
Spring Security 次要平安过滤器的执行曾经靠近序幕,然而这个 FilterSecurityInterceptor 是重头戏。
FilterSecurityInterceptor 次要实现如下工作:
- 解析以后申请的平安配置,次要包含:permitAll、authenticated、denyAll、anonymous 等。
- 从 SecurityContextHolder 获取平安认证信息。
- 依据以后申请的平安配置信息及以后用户的平安认证信息进行认证投票,其实就是判断获取到的以后用户的平安认证信息是否合乎配置的平安认证需要,合乎的话则通过认证,不合乎的话抛出 accesssdeny 异样。
之所以说 FilterSecurityInterceptor 是 Spring Security 平安过滤器的重头戏,是因为咱们依据我的项目的具体需要、针对不同申请配置好的平安认证规范的解析是 FilterSecurityInterceptor 实现的,解析之后查看以后用户是否满足申请所须要的平安要求也是 FilterSecurityInterceptor 实现的。
如果以后用户认证信息不满足以后申请的平安需要,比方匿名用户拜访 /helloworld、/helloworld 配置为 authenticated 的话,FilterSecurityInterceptor 会抛出 accesssdeny 异样,最终经 ExceptionTranslationFilter 解决之后前台页面会收到 403 错误信息。
总结
Spring security 次要平安过滤器的根本工作原理剖析结束,其实每一个平安过滤器的底层工作细节都能够独自写一篇文章进行代码级的剖析。然而一般来讲,对于绝对简单一点的常识,入门学习的时候太过细节的剖析会影响到对整体框架的了解,Spring Security 绝对来讲比拟负责,因而适宜这一准则。
上一篇 Spring Security 的初始化过程(3)