Spring Security学习笔记之SessionManagementFilter
2016-10-11 17:38
495 查看
开始的时候不明白这个过滤器的作用是什么. 看源码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
...
if (!securityContextRepository.containsContext(request)) {
// 这时这个authentication可能是RemembermeAuthentication, 或AnonymousAuthentication的实例
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the session strategy
try {
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
} catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug("SessionAuthenticationStrategy rejected the authentication object", e);
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
// Eagerly save the security context to make it available for any possible re-entrant
// requests which may occur before the current request completes. SEC-1396.
securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
} else {
// No security context or authentication present. Check for a session timeout
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
if(logger.isDebugEnabled()) {
logger.debug("Requested session ID " + request.getRequestedSessionId() + " is invalid.");
}
if (invalidSessionStrategy != null) {
invalidSessionStrategy.onInvalidSessionDetected(request, response);
return;
}
}
}
}
chain.doFilter(request, response);
}
当请求所在的session里没有设置"SPRING_SECURITY_CONTEXT"属性的时候, 才会被这个过滤器拦截. 否则跳到下一个过滤器. 但这个"SPRING_SECURITY_CONTEXT"属性是在用户登录验证完成后就放进session里的(具体参考AbstractAuthenticationProcessingFilter.successfulAuthentication()方法), 所以登录成功后的每一个请求, 它的session里都会有这个属性, 所以就不会被这个过滤器拦截.
后来发现有两种情况, 用户发出的请求会被这个过滤器拦截:
1. 当用户重启浏览器, 然后使用remember-me授权成功后, 再直接访问授权后的url. 这时, session里没有了"SPRING_SECURITY_CONTEXT"属性. 那么这个请求会被此过滤器拦截. 这时得到的authentication是RemembermeAuthentication的实例.)
2. 当session因过期而被容器自动销毁时, 若用户继续发出请求, 这个请求会放在一个新的session里, 新session里没有设置"SPRING_SECURITY_CONTEXT"属性, 那么这个请求也会被这个过滤器拦截. 这时得到的authentication是AnonymousAuthentication的实例.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
...
if (!securityContextRepository.containsContext(request)) {
// 这时这个authentication可能是RemembermeAuthentication, 或AnonymousAuthentication的实例
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the session strategy
try {
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
} catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug("SessionAuthenticationStrategy rejected the authentication object", e);
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
// Eagerly save the security context to make it available for any possible re-entrant
// requests which may occur before the current request completes. SEC-1396.
securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
} else {
// No security context or authentication present. Check for a session timeout
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
if(logger.isDebugEnabled()) {
logger.debug("Requested session ID " + request.getRequestedSessionId() + " is invalid.");
}
if (invalidSessionStrategy != null) {
invalidSessionStrategy.onInvalidSessionDetected(request, response);
return;
}
}
}
}
chain.doFilter(request, response);
}
当请求所在的session里没有设置"SPRING_SECURITY_CONTEXT"属性的时候, 才会被这个过滤器拦截. 否则跳到下一个过滤器. 但这个"SPRING_SECURITY_CONTEXT"属性是在用户登录验证完成后就放进session里的(具体参考AbstractAuthenticationProcessingFilter.successfulAuthentication()方法), 所以登录成功后的每一个请求, 它的session里都会有这个属性, 所以就不会被这个过滤器拦截.
后来发现有两种情况, 用户发出的请求会被这个过滤器拦截:
1. 当用户重启浏览器, 然后使用remember-me授权成功后, 再直接访问授权后的url. 这时, session里没有了"SPRING_SECURITY_CONTEXT"属性. 那么这个请求会被此过滤器拦截. 这时得到的authentication是RemembermeAuthentication的实例.)
2. 当session因过期而被容器自动销毁时, 若用户继续发出请求, 这个请求会放在一个新的session里, 新session里没有设置"SPRING_SECURITY_CONTEXT"属性, 那么这个请求也会被这个过滤器拦截. 这时得到的authentication是AnonymousAuthentication的实例.
相关文章推荐
- Spring Security3源码分析(14)-SessionManagementFilter分析-下
- Spring Security学习笔记之ChannelProcessingFilter
- Spring Security3源码分析-SessionManagementFilter分析--下
- MVC使用Controller代替Filter完成登录验证(Session校验)学习笔记5
- Spring Security3源码分析(13)-SessionManagementFilter分析-上
- MVC使用Controller代替Filter完成登录验证(Session校验)学习笔记5
- Spring Security学习笔记之RememberMeAuthenticationFilter
- Spring Security3源码分析-SessionManagementFilter分析-上
- MonoRail学习笔记六:Filter功能使用
- Apache CMS学习笔记2 - Session
- {传智播客} (学习笔记)--Hibernate的Session缓存问题与理解
- Hibernate学习笔记:理解一级缓存和session清理
- session和cookie学习笔记
- Servlet 学习笔记7:HttpSession
- MonoRail学习笔记六:Filter功能使用
- 学习笔记: CIC filter及其matlab实现
- UrlRewriteFilter 学习笔记
- JBoss SSO学习笔记3 Identity Management Framework
- Hibernate学习笔记:session操作对象
- Introduction to Materials Management 学习笔记--生产计划系统