一、SpringSecurity 過濾器鏈:
1、SecurityContextPersistenceFilter 會在請求開始時從配置好的SecurityContextRepository中獲取SecurityContext,然后把它設置給SecurityContextHolder。
在請求完成后將SecurityContextHolder持有的SecurityContext再保存到配置好的SecurityContextRepository,同時清除SecurityContextHolder所持有的SecurityContext。
2、
UsernamePasswordAuthenticationFilter用於處理來自表單提交的認證,認證成功由
AuthenticationSuccessHandler處理,反之由
AuthenticationFailureHandler處理。
3、FilterSecurityInterceptor用於保護Http資源(授權),它需要引用AccessDecisionManager(決策管理器)、AuthenticationManager(認證管理器)、 SecurityMetadataSource(資源與權限的對應關系)。
4、ExceptionTranslationFilter 只會處理 AuthenticationException、AccessDeniedException異常,其他的異常會拋出。
二、基於用戶名、密碼認證、授權流程:
1、AbstractAuthenticationProcessingFilter.attemptAuthentication()開始用戶認證流程,在這里會處理認證的成功(AuthenticationSuccessHandler)或失敗(AuthenticationFailureHandler);
2、重寫UsernamePasswordAuthenticationFilter.attemptAuthentication()調用retrieveUser()方法,自定義用戶名、密碼、驗證碼校驗、認證邏輯,返回Authentication對象實例存入SessionAuthenticationStrategy;
3、繼承AbstractUserDetailsAuthenticationProvider重寫retrieveUser方法,開始處理用戶認證,調用DetailsServiceImpl.loadUserByUsername()返回UserDetails對象實例;
4、實現UserDetailsService重寫loadUserByUsername,自定義用戶名密碼校驗流程,成功返回UserDetails對象實例,否則拋出AuthenticationException類異常;用戶認證結束;
5、FilterSecurityInterceptor.beforeInvocation()過濾器開始授權流程,實例化AccessDecisionManager(授權管理器)、AuthenticationManager(認證管理器)、FilterInvocationSecurityMetadataSource(處理url、權限關系的接口);
6、進入AbstractSecurityInterceptor.beforeInvocation(Object object)進行授權,分為三步開始處理。
6.1.Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);//獲取當前url的權限
6.2.Authentication authenticated = authenticateIfRequired();//獲取Authenticatio實例,拿到當前用戶信息
6.3.this.accessDecisionManager.decide(authenticated, object, attributes);//沒有權限拋出AccessDeniedException類異常 ExceptionTranslationFilter處理異常
三、“記住我”功能實現原理:

1、用戶第一次登陸,AbstractAuthenticationProcessingFilter 開始用戶認證,成功后 RememberMeServices 實現類 AbstractRememberMeServices
作業務處理。
PersistentTokenBasedRememberMeServices 繼承了 AbstractRememberMeServices,重寫了 onLoginSucce(),存儲 PersistentTokenRepository 對象到DB。
public class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices { private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl(); ...... protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { String username = successfulAuthentication.getName(); this.logger.debug("Creating new persistent login for user " + username); PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, this.generateSeriesData(), this.generateTokenData(), new Date()); try { this.tokenRepository.createNewToken(persistentToken); this.addCookie(persistentToken, request, response); } catch (Exception var7) { this.logger.error("Failed to save persistent token ", var7); } } ...... }
2、第二次登陸 RememberMeAuthenticationFilter 處理
public class RememberMeAuthenticationFilter extends GenericFilterBean implements ApplicationEventPublisherAware { ...... public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res; if (SecurityContextHolder.getContext().getAuthentication() == null) { Authentication rememberMeAuth = this.rememberMeServices.autoLogin(request, response);// 解碼cookie獲取token,拿到UserDetails對象 if (rememberMeAuth != null) { try { rememberMeAuth = this.authenticationManager.authenticate(rememberMeAuth);//認證開始 SecurityContextHolder.getContext().setAuthentication(rememberMeAuth); this.onSuccessfulAuthentication(request, response, rememberMeAuth); if (this.logger.isDebugEnabled()) { this.logger.debug("SecurityContextHolder populated with remember-me token: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } if (this.eventPublisher != null) { this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(SecurityContextHolder.getContext().getAuthentication(), this.getClass())); } if (this.successHandler != null) { this.successHandler.onAuthenticationSuccess(request, response, rememberMeAuth); return; } } catch (AuthenticationException var8) { if (this.logger.isDebugEnabled()) { this.logger.debug("SecurityContextHolder not populated with remember-me token, as AuthenticationManager rejected Authentication returned by RememberMeServices: '" + rememberMeAuth + "'; invalidating remember-me token", var8); } this.rememberMeServices.loginFail(request, response);//失敗跳轉到登錄頁 this.onUnsuccessfulAuthentication(request, response, var8); } } chain.doFilter(request, response); } else { if (this.logger.isDebugEnabled()) { this.logger.debug("SecurityContextHolder not populated with remember-me token, as it already contained: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } chain.doFilter(request, response); } } }