Spring Security3默认过滤器链的第一个过滤器就是org.springframework.security.web.context.SecurityContextPersistenceFilter,这个Filter就是持久化SecurityContext实例的,流程图:
看SecurityContextPersistenceFilter代码:
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
chain.doFilter(request, response);
return;
}
final boolean debug = logger.isDebugEnabled();
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
if (forceEagerSessionCreation) {
HttpSession session = request.getSession();
if (debug && session.isNew()) {
logger.debug("Eagerly created session: " + session.getId());
}
}
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
// 从SecurityContextRepository中获取SecurityContext实例
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
try {
// 将SecurityContext实例到SecurityContextHolder中,后面的过滤器以及我们在程序中一般都从这个holder中拿SecurityContext实例
SecurityContextHolder.setContext(contextBeforeChainExecution);
chain.doFilter(holder.getRequest(), holder.getResponse());
} finally {
// 先获取SecurityContext实例
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
// Crucial removal of SecurityContextHolder contents - do this before anything else.
//再从holder中清除
SecurityContextHolder.clearContext();
// 当SecurityContext实例被update,或session中SecurityContext实例为空,将其放入session中
repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
if (debug) {
logger.debug("SecurityContextHolder now cleared, as request processing completed");
}
}
}
分析一下HttpSessionSecurityContextRepository的loadContext方法:
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
HttpServletRequest request = requestResponseHolder.getRequest();
HttpServletResponse response = requestResponseHolder.getResponse();
HttpSession httpSession = request.getSession(false);
// 从session中获取SecurityContext对象
SecurityContext context = readSecurityContextFromSession(httpSession);
if (context == null) {
if (logger.isDebugEnabled()) {
logger.debug("No SecurityContext was available from the HttpSession: " + httpSession +". " +
"A new one will be created.");
}
// 如果SecurityContext对象是空的,创建一个SecurityContext实例
context = generateNewContext();
}
// 注意:此处用SaveToSessionResponseWrapper替换了原生的httpresponse对象,可能和自定义的response wrapper对象有冲突。
requestResponseHolder.setResponse(new SaveToSessionResponseWrapper(response, request,
httpSession != null, context.hashCode()));
return context;
}
这个过滤器比较简单,它维护了SecurityContextHolder中SecurityContext实例,我们也很方便的从SecurityContextHolder中获取SecurityContext对象