1.SecurityContextPersistenceFilter 是干啥的
SecurityContextPersistenceFilter
是用来在认证之前从SecurityContextRepository
获取SecurityContext
,然后放入SecurityContextHolder
中。
然后在其他filter执行完毕之后,再将SecurityContext
通过SecurityContextRepository
存储到想要存储的地方,然后清理掉SecurityContextHolder
中的SecurityContext
2.doFilter源码解读
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getAttribute(FILTER_APPLIED) != null) {
// ensure that filter is only applied once per request
// 这个就是确保一个request只会走一次SecurityContextPersistenceFilter
chain.doFilter(request, response);
return;
}
final boolean debug = logger.isDebugEnabled();
// 给request打标记,说明这个Filter已经执行过一次了。
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
if (forceEagerSessionCreation) {
// 要不要先创建session
HttpSession session = request.getSession();
if (debug && session.isNew()) {
logger.debug("Eagerly created session: " + session.getId());
}
}
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
response);
// 通过SecurityContextRepository加载SecurityContext
// 默认使用的是HttpSessionSecurityContxtReposity
// 这个就是说,默认是从session中获取。如果session里面获取不到就创建一个新的SecurityContext
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
try {
// 将 SecurityContext 丢入 SecurityContextHolder
SecurityContextHolder.setContext(contextBeforeChainExecution);
// 执行其他拦截器
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
// 在其他拦截器执行完后,再将SecurityContext 从 SecurityContextHolder中移除
SecurityContext contextAfterChainExecution = SecurityContextHolder
.getContext();
// Crucial removal of SecurityContextHolder contents - do this before anything
// else.
SecurityContextHolder.clearContext();
// 保存经过其他拦截器操作过后的SecurityContext到指定地方
//repo的默认值是HttpSessionSecurityContxtReposity
// 也就是保存到session中去
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
holder.getResponse());
// ok,这个filter执行完毕,移除重复标记
request.removeAttribute(FILTER_APPLIED);
if (debug) {
logger.debug("SecurityContextHolder now cleared, as request processing completed");
}
}
}
简述流程:
1.从SecurityContextRepository
中获取SecurityContext
2.将SecurityContext
存入SecurityContextHolder
中
3.执行其他过滤器,对SecurityContext
进行处理
4.在其他的执行完后,将SecurityContext
从SecurityContextHolder
中清除,并通过SecurityContextRepository
进行回写。
3.题外话之默认的HttpSessionSecurityContextRepository
这是默认的SecurityContext
的存储器。其实就是将SecurityContext
存储在session中。
从上面我们可以看到,从session中拿SecurityContext
和存SecurityContext
的过程。
同时我们也可以仿造HttpSessionSecurityContextRepository
去实现我们自己的SecurityContextRepository
。完成对SecurityContext
的储存。
4.小结
在这个类中,我们可以看到如何保证filter只执行一次。如何对SecurityContext的生命周期的把控。以及最关键的SecurityContext的存储机制和时机。