SecurityContextPersistenceFilter是承接容器的session与spring security的重要filter,主要工作是从session中获取SecurityContext,然后放到上下文中,之后的filter大多依赖这个来获取登录态。其主要是通过HttpSessionSecurityContextRepository来存取的。
public class SecurityContextPersistenceFilter extends GenericFilterBean {
static final String FILTER_APPLIED = "__spring_security_scpf_applied";
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) {
// 这个就是确保一个request只会走一次SecurityContextPersistenceFilter
chain.doFilter(request, response);
return;
}
// 给request打标记,说明这个Filter已经执行过一次了。
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
if (forceEagerSessionCreation) {
// 要不要先创建session
HttpSession session = request.getSession();
}
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();
SecurityContextHolder.clearContext();
// 保存经过其他拦截器操作过后的SecurityContext到指定地方
//repo的默认值是HttpSessionSecurityContxtReposity
// 也就是保存到session中去
repo.saveContext(contextAfterChainExecution, holder.getRequest(),holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
}
}
}
简述流程:
1.从SecurityContextRepository中获取SecurityContext
2.将SecurityContext存入SecurityContextHolder中
3.执行其他过滤器,对SecurityContext进行处理
4.在其他的执行完后,将SecurityContext从SecurityContextHolder中清除,并通过SecurityContextRepository进行回写。
Spring Security Web提供的类HttpSessionSecurityContextRepository是一个SecurityContextRepository接口的实现,用于在HttpSession中保存安全上下文(security context),这样属于同一个HttpSession的多个请求,就能够利用此机制访问同一安全上下文了。
public interface SecurityContextRepository {
//获取所提供请求的安全上下文。对于未经身份验证的用户,应返回空上下文实现。此方法不应返回null。
SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
//在请求完成时存储安全上下文。
void saveContext(SecurityContext context, HttpServletRequest request,HttpServletResponse response);
//允许查询存储库是否包含当前请求的安全上下文。
boolean containsContext(HttpServletRequest request);
}