staticfinal String FILTER_APPLIED ="__spring_security_session_mgmt_filter_applied";privatefinal SecurityContextRepository securityContextRepository;private SessionAuthenticationStrategy sessionAuthenticationStrategy;private AuthenticationTrustResolver trustResolver =newAuthenticationTrustResolverImpl();private InvalidSessionStrategy invalidSessionStrategy = null;private AuthenticationFailureHandler failureHandler =newSimpleUrlAuthenticationFailureHandler();publicvoiddoFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {
HttpServletRequest request =(HttpServletRequest) req;
HttpServletResponse response =(HttpServletResponse) res;if(request.getAttribute(FILTER_APPLIED)!= null){
chain.doFilter(request, response);return;}
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);// 允许查询存储库是否包含当前请求的安全上下文。if(!securityContextRepository.containsContext(request)){
// 获取当前已认证的主体或认证请求令牌。
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{
// 发生新的身份验证时,执行与Http会话相关的功能。
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.// 认真保存安全上下文,以使其可用于在当前请求完成之前可能发生的任何可重入请求。 SEC-1396。
securityContextRepository.saveContext(SecurityContextHolder.getContext(),
request, response);}else{
// No security context or authentication present. Check for a session// timeoutif(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);}
ExceptionTranslationFilter
private ThrowableAnalyzer throwableAnalyzer =newDefaultThrowableAnalyzer();publicvoiddoFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {
HttpServletRequest request =(HttpServletRequest) req;
HttpServletResponse response =(HttpServletResponse) res;try{
chain.doFilter(request, response);
logger.debug("Chain processed normally");}catch(IOException ex){
throw ex;}catch(Exception ex){
// Try to extract a SpringSecurityException from the stacktrace// 尝试从 stacktrace 中提取 SpringSecurityException
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);// 从传入的数组中返回可分配给所提供类型的第一个throwable。// 返回的实例可以安全地强制转换为指定的类型。// 如果传入的数组为null或为空,则此方法返回null。
RuntimeException ase =(AuthenticationException) throwableAnalyzer
.getFirstThrowableOfType(AuthenticationException.class, causeChain);if(ase == null){
ase =(AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(
AccessDeniedException.class, causeChain);}if(ase != null){
if(response.isCommitted()){
thrownewServletException("Unable to handle the Spring Security Exception because the response is already committed.", ex);}handleSpringSecurityException(request, response, chain, ase);}else{
// Rethrow ServletExceptions and RuntimeExceptions as-is// 照原样扔回 ServletException 和 RuntimeExceptionif(ex instanceofServletException){
throw(ServletException) ex;}elseif(ex instanceofRuntimeException){
throw(RuntimeException) ex;}// Wrap other Exceptions. This shouldn't actually happen// as we've already covered all the possibilities for doFilter// 包装其他异常。 // 实际上,这应该不应该发生,因为我们已经介绍了doFilter的所有可能性thrownewRuntimeException(ex);}}}
FilterSecurityInterceptor
privatestaticfinal String FILTER_APPLIED ="__spring_security_filterSecurityInterceptor_filterApplied";privateboolean observeOncePerRequest =true;/**
* Method that is actually called by the filter chain. Simply delegates to the
* {@link #invoke(FilterInvocation)} method.
* 筛选器链实际调用的方法。只需委托给 {@link #invoke(FilterInvocation)}方法即可。
*
* @param request the servlet request
* @param response the servlet response
* @param chain the filter chain
*
* @throws IOException if the filter chain fails
* @throws ServletException if the filter chain fails
*/publicvoiddoFilter(ServletRequest request, ServletResponse response,
FilterChain chain)throws IOException, ServletException {
FilterInvocation fi =newFilterInvocation(request, response, chain);invoke(fi);}publicvoidinvoke(FilterInvocation fi)throws IOException, ServletException {
if((fi.getRequest()!= null)&&(fi.getRequest().getAttribute(FILTER_APPLIED)!= null)&& observeOncePerRequest){
// filter already applied to this request and user wants us to observe// once-per-request handling, so don't re-do security checking// 已应用于此请求的过滤器,用户希望我们遵守每个请求一次的处理,因此请勿重新进行安全检查
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else{
// first time this request being called, so perform security checking// 第一次调用此请求,因此请执行安全检查if(fi.getRequest()!= null && observeOncePerRequest){
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);}
InterceptorStatusToken token =super.beforeInvocation(fi);try{
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}finally{
// 安全对象调用完成后,清理 AbstractSecurityInterceptor 的工作。// 无论安全对象调用是否成功返回,都应在安全对象调用之后和 afterInvocation 之前调用此方法(即应在finally块中完成)。super.finallyInvocation(token);}// 安全对象调用完成后,完成 AbstractSecurityInterceptor 的工作。super.afterInvocation(token, null);}}