Spring Security基礎(chǔ)原理

簡介

Spring Security:是一個提供身份驗證,授權(quán)和保護以防止常見攻擊的框架。 憑借對命令式和反應(yīng)式應(yīng)用程序的一流支持,它為Spring應(yīng)用程序的安全提供實際標(biāo)準(zhǔn)。

特性

Spring Security為身份驗證,授權(quán)和針對常見漏洞的防護提供了全面的支持。 它還集成了三方庫,以簡化其使用。

認(rèn)證

Spring Security為身份驗證提供了全面的支持。 身份驗證是我們驗證誰試圖訪問特定資源的身份的方法。 驗證用戶身份的常用方法是要求用戶輸入用戶名和密碼。 一旦執(zhí)行了身份驗證,我們就會知道身份并可以執(zhí)行授權(quán)。

認(rèn)證支持

Spring Security提供了用于驗證用戶的內(nèi)置支持。 分為兩大主體:基于Servlet和WebFlux的身份驗證。

密碼加密存儲

Spring Security的PasswordEncoder接口用于對密碼進行單向轉(zhuǎn)換,以使密碼可以安全地存儲。

基于PasswordEncoder接口的實現(xiàn)類如下:

  • DelegatingPasswordEncoder:即委托密碼編碼器,兼容多種不同加密方式存儲密碼。主要用于新舊數(shù)據(jù)的加密方式的兼容,做到平滑遷移,例如舊數(shù)據(jù)使用NoOpPasswordEncoder,新數(shù)據(jù)使用BCryptPasswordEncoder加密。

  • BCryptPasswordEncoder:基于bcrypt算法的編碼器,為了使其更能抵御密碼破解,bcrypt故意降低了速度,與其他自適應(yīng)單向功能一樣,應(yīng)將其調(diào)整為大約1秒鐘,以驗證系統(tǒng)上的密碼。BCryptPasswordEncoder的默認(rèn)實現(xiàn)使用強度10。

  • Argon2PasswordEncoder:基于 Argon2算法的編碼器,Argon2是“密碼哈希競賽”的獲勝者。 為了克服自定義硬件上的密碼破解問題,Argon2是一種故意慢速的算法,需要大量內(nèi)存。 與其他自適應(yīng)單向功能一樣,應(yīng)將其調(diào)整為大約1秒鐘,以驗證系統(tǒng)上的密碼。 Argon2PasswordEncoder的當(dāng)前實現(xiàn)需要BouncyCastle。

  • Pbkdf2PasswordEncoder:基于 PBKDF2算法的編碼器,為了克服密碼破解問題,PBKDF2是一種故意緩慢的算法。 與其他自適應(yīng)單向功能一樣,應(yīng)將其調(diào)整為大約1秒鐘,以驗證系統(tǒng)上的密碼。 當(dāng)需要FIPS認(rèn)證時,此算法是一個不錯的選擇。

  • SCryptPasswordEncoder:基于 scrypt算法的編碼器, 為了克服自定義硬件scrypt上的密碼破解問題,這是一種故意緩慢的算法,需要大量內(nèi)存。 與其他自適應(yīng)單向功能一樣,應(yīng)將其調(diào)整為大約1秒鐘,以驗證系統(tǒng)上的密碼。

防止漏洞利用

  • CSRF:Cross Site Request Forgery,即跨站請求偽造。Spring提供了兩種機制來防御CSRF攻擊:1、基于token表單驗證(表單增加_csrf字段);2、在會話Cookie上指定SameSite屬性;

  • 安全的HTTP響應(yīng)頭:

    • Cache Control:Spring Security的默認(rèn)禁用緩存以保護用戶的內(nèi)容,Cache-Control: no-cache, no-store, max-age=0, must-revalidate
      Pragma: no-cache
      Expires: 0
    • Content Type Options:禁用內(nèi)容嗅探X-Content-Type-Options: nosniff防止XSS攻擊;
    • HTTP Strict Transport Security (HSTS):嚴(yán)格的安全傳輸HTTP,將http請求自動轉(zhuǎn)為https請求,Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload;
    • X-Frame-Options:Spring Security默認(rèn)禁用iframe頁面,X-Frame-Options: DENY
    • X-XSS-Protection:通常瀏覽器在檢測到XSS攻擊時應(yīng)采取的措施。 例如,過濾器可能會嘗試以最小侵入性的方式更改內(nèi)容以仍然呈現(xiàn)所有內(nèi)容。 有時,這種替換本身可能會成為XSS漏洞。 相反,最好是阻止內(nèi)容,而不要嘗試對其進行修復(fù)。 Spring Security默認(rèn)阻止內(nèi)容:X-XSS-Protection: 1; mode=block
    • Content Security Policy (CSP):內(nèi)容安全策略是Web應(yīng)用程序可以用來緩解諸如跨站點腳本(XSS)之類的內(nèi)容注入漏洞的機制。
    • Referrer Policy:Referrer Policy: strict-origin-when-cross-origin;

認(rèn)證原理分析(Servlet)

過濾器

DelegatingFilterProxy

Spring提供了一個名為DelegatingFilterProxy的Filter實現(xiàn),可以在Servlet容器的生命周期和Spring的ApplicationContext之間進行橋接。 Servlet容器允許使用自己的標(biāo)準(zhǔn)注冊Filters,但是它不知道Spring定義的Bean。 DelegatingFilterProxy可以通過標(biāo)準(zhǔn)的Servlet容器機制進行注冊,然后將所有工作委托給實現(xiàn)Filter的Spring Bean。


image.png

如上圖所示,DelegatingFilterProxy是一個標(biāo)準(zhǔn)的Servlet Filter,當(dāng)調(diào)用鏈路到DelegatingFilterProxy,DelegatingFilterProxy會找到達Spring管理的Filter,然后發(fā)起調(diào)用。

FilterChainProxy

image.png

如上圖所示,F(xiàn)ilterChainProxy是Spring Security提供的特殊過濾器,允許通過SecurityFilterChain委派許多過濾器實例。

SecurityFilterChain

image.png

如上圖所示,F(xiàn)ilterChainProxy使用SecurityFilterChain確定應(yīng)對此請求調(diào)用哪些Spring Security過濾器。

Security Filter是注冊到FilterChainProxy而不是DelegatingFilterProxy的。原因如下:

  • 它為Spring Security的所有Servlet支持提供了一個起點。如果想對Spring Security的Servlet支持進行故障排除,那么在FilterChainProxy中添加調(diào)試點是一個很好的起點;
  • 它清除SecurityContext以避免內(nèi)存泄漏;
  • 它使用Spring Security的HttpFirewall來保護應(yīng)用程序免受某些類型的攻擊;
  • 它在確定何時應(yīng)調(diào)用SecurityFilterChain時提供了更大的靈活性。 在Servlet容器中,僅根據(jù)URL調(diào)用過濾器。 但是,F(xiàn)ilterChainProxy可以利用RequestMatcher接口,根據(jù)HttpServletRequest中的任何內(nèi)容確定調(diào)用。
  • FilterChainProxy可用于確定應(yīng)使用哪個SecurityFilterChain。 這允許應(yīng)用程序的不同部分提供完全獨立的配置。


    image.png

    如上圖所示,F(xiàn)ilterChainProxy利用RequestMatcher接口確定調(diào)用哪個SecurityFilterChain。舉個例子:如果訪問/api/getMsg,則調(diào)用SecurityFilterChain0。

Security Filter

Spring Security提供了以下Security Filter(包含順序,通過FilterComparator配置相關(guān)順序):

  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

異常處理

image.png

如上圖表示的是異常處理過濾器ExceptionTranslationFilter的工作原理:

  • ExceptionTranslationFilter 調(diào)用 FilterChain.doFilter(request, response),拋出Security Exception;
  • 如果用戶未通過身份驗證或它是AuthenticationException,則啟動身份驗證:
    • 清除SecurityContextHolder;
    • 將HttpServletRequest保存在RequestCache中;
    • 進入AuthenticationEntryPoint(重定向到登錄頁或者返回401);
  • 另外一種異常就是,訪問被拒絕,則交給AccessDeniedHandler來處理。
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
            FilterChain chain, RuntimeException exception) throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
        }
        else if (exception instanceof AccessDeniedException) {
            handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
        }
    }

認(rèn)證

認(rèn)證相關(guān)組件

  • SecurityContextHolder:用于存儲SecurityContext;

  • SecurityContext:用于存儲Authentication;

  • Authentication:用戶存儲用戶認(rèn)證詳細信息;
    image.png

    該圖為SecurityContextHolder、SecurityContext、Authentication三者之間的關(guān)系。

  • AuthenticationManager:統(tǒng)一管理執(zhí)行身份驗證;

  • ProviderManager:AuthenticationManager最常見的實現(xiàn);

  • AuthenticationProvider:用于執(zhí)行特定類型的身份驗證,由ProviderManager統(tǒng)一管理。


    image.png
image.png

如上圖所示,ProviderManager作為AuthenticationManager最常見的實現(xiàn),ProviderManager認(rèn)證時,將認(rèn)證邏輯委托給AuthenticationProvider列表,不同AuthenticationProvider的執(zhí)行不同的認(rèn)證邏輯。

如果沒有AuthenticationProvider可以執(zhí)行身份驗證,使用該父AuthenticationManager(通常是ProviderManager實例)進行認(rèn)證。


image.png

一個父AuthenticationManager可能存在多個ProviderManager實例。 即具有相同身份驗證(共享父AuthenticationManager)但又具有不同身份驗證機制(不同ProviderManager實例)。

  • AuthenticationEntryPoint:認(rèn)證入口,用戶未登錄時,重定向到登錄頁面或者發(fā)送401、WWW-Authenticate響應(yīng)頭;ExceptionTranslationFilter 拋出AuthenticationException的時候,調(diào)用sendStartAuthentication方法時進入AuthenticationEntryPoint邏輯。

  • AbstractAuthenticationProcessingFilter:作為身份驗證的基本過濾器(formLogin表單登錄)。 當(dāng)用戶提交身份憑據(jù)(例如,賬號密碼)時過濾。
    image.png

    上圖表示用戶提交身份憑據(jù)的認(rèn)證邏輯:

  1. 假設(shè)用戶在登錄頁提交表單(賬號密碼)進行登錄;
  2. AbstractAuthenticationProcessingFilter判斷該請求是提交身份憑據(jù)認(rèn)證請求,則調(diào)用attemptAuthentication方法也就是上圖中的①;
  3. attemptAuthentication將認(rèn)證邏輯委托給AuthenticationManager就是上圖中的②;
  4. 認(rèn)證失敗會做一些清理動作就是上圖中的③;
  5. 認(rèn)證成功,作Session相關(guān)的邏輯、將Authentication存儲到SecurityContextHolder、RememberMe相關(guān)處理、認(rèn)證成功事件的發(fā)布、認(rèn)證成功的后置處理。
  • SessionAuthenticationStrategy:旨在身份驗證時對HttpSession相關(guān)行為進行管理,如會話固定保護,csrf防護,session并發(fā)控制等。
    image.png

    如上圖所示,兩種登錄方式:UsernamePasswordAuthenticationFilter(基于表單)與BasicAuthenticationFilter(基于Rest)。有兩條請求鏈路:

    • 客戶端請求經(jīng)過UsernamePasswordAuthenticationFilter過濾器,驗證用戶登錄憑證后,調(diào)用SessionAuthenticationStrategy.onAuthentication()基于session的驗證;
    • 客戶端請求經(jīng)過BasicAuthenticationFilter過濾器,驗證用戶登錄憑證后,需要再經(jīng)過SessionManagementFilter過濾器,SessionManagementFilter接著將session驗證委托給SessionAuthenticationStrategy。


      image.png

      上圖SessionAuthenticationStrategy的調(diào)用邏輯:

    • 首先進入CompositeSessionAuthenticationStrategy,該策略意為混合session認(rèn)證策略,它把session認(rèn)證邏輯循環(huán)委托給其他具體的策略;
    • ConcurrentSessionControlAuthenticationStrategy,并發(fā)session控制,用于同一個用戶多次登錄管理,默認(rèn)行為會剔除(標(biāo)記過期SessionInformation.expireNow())最近最久沒有使用的登錄,maximumSessions=1配置一個賬號最多幾個登錄共存;
    • ChangeSessionIdAuthenticationStrategy,顧名思義變更當(dāng)前sessionId,目的為了會話固定防護,該類繼承了AbstractSessionFixationProtectionStrategy。
    • RegisterSessionAuthenticationStrategy,為當(dāng)前的新的sessionId注冊一個SessionInformation(為了支持并發(fā)session控制);
    • CsrfAuthenticationStrategy,支持csrf防護,生成新的token。

講到這里大家可能會有疑問,剛才提到SessionInformation是干么用的呢?
SessionInformation是為了支持session并發(fā)控制,ConcurrentSessionControlAuthenticationStrategy只是將SessionInformation標(biāo)記為過期,等下次請求的時候會經(jīng)過ConcurrentSessionFilter過濾器,此時會判斷當(dāng)前session對應(yīng)的SessionInformation是否被標(biāo)記過期了,如果是則調(diào)用session銷毀動作,真正地登出。如果不是,得刷新更新SessionInformation的lastRequest(最近一次請求時間),ConcurrentSessionControlAuthenticationStrategy是基于該時間去剔除最近最久沒有使用的登錄。

認(rèn)證機制

  • Username and Password
  • Remember Me
  • CAS
  • OAuth 2.0
  • SAML 2.0
  • JAAS Authentication
  • OpenID
  • Pre-Authentication Scenarios
  • X509 Authentication

Username and Password認(rèn)證

驗證用戶身份的最常見方法之一是驗證用戶名和密碼, Spring Security為使用用戶名和密碼進行身份驗證提供了全面的支持。

認(rèn)證方式
  • Form Login:基于表單登錄認(rèn)證;


    image.png

    上圖表示未登錄用戶第一次訪問web系統(tǒng)Spring Security處理流程:

  1. 用戶在瀏覽器發(fā)起請求web系統(tǒng)私有資源 /private
  2. SecurityFilterChain過濾器鏈路到達FilterSecurityInterceptor,并拋出訪問被拒絕的異常AccessDeniedException,ExceptionTranslationFilter捕獲該異常并通過sendStartAuthentication方法進入LoginUrlAuthenticationEntryPoint(AuthenticationEntryPoint的實現(xiàn)類);
  3. LoginUrlAuthenticationEntryPoint設(shè)置了一個重定向到/login頁面的響應(yīng)頭;
  4. 瀏覽器重定向到/login,并獲取到login.html,即登錄主頁面。
    image.png

上圖表示用戶在表單提交用戶名、密碼的驗證流程:

  1. 用戶提交表單,進入UsernamePasswordAuthenticationFilter過濾器,通過調(diào)用attemptAuthentication方法將用戶名、密碼包裝成UsernamePasswordAuthenticationToken對象,并傳給AuthenticationManager;


    image.png

    上圖表示AuthenticationManager工作流程:

    1. 將UsernamePasswordAuthenticationToken傳給AuthenticationManager;
    2. ProviderManager將認(rèn)證邏輯委托為DaoAuthenticationProvider;
    3. DaoAuthenticationProvider調(diào)用UserDetailsService的loadUserByUsername方法獲取UserDetails,通過PasswordEncoder比較用戶請求傳遞過來UsernamePasswordAuthenticationToken上的密碼與UserDetails存儲的密碼是否一致;
    4. 認(rèn)證成功,將UserDetails作為principal,UserDetails的authorities作為authorities包裝成UsernamePasswordAuthenticationToken返回。
  1. 認(rèn)證失敗會做一些清理動作;
  2. 認(rèn)證成功,作Session相關(guān)的邏輯、將Authentication存儲到SecurityContextHolder、RememberMe相關(guān)處理、認(rèn)證成功事件的發(fā)布、認(rèn)證成功的后置處理。
  • Basic Authentication:基礎(chǔ)認(rèn)證,基本HTTP REST的身份驗證。


    image.png

    上圖表示未登錄用戶第一次訪問web系統(tǒng)Spring Security處理流程:

  1. 用戶在瀏覽器發(fā)起請求web系統(tǒng)私有資源 /private;
  2. SecurityFilterChain過濾器鏈路到達FilterSecurityInterceptor,并拋出訪問被拒絕的異常AccessDeniedException,ExceptionTranslationFilter捕獲該異常并通過sendStartAuthentication方法進入BasicAuthenticationEntryPoint(AuthenticationEntryPoint的實現(xiàn)類);
  3. BasicAuthenticationEntryPoint設(shè)置了WWW-Authenticate響應(yīng)頭及401響應(yīng)碼并返回。
    image.png

上圖表示當(dāng)客戶端收到WWW-Authenticate響應(yīng)頭時,使用用戶名和密碼登錄的流程:

  1. 當(dāng)用戶提交其用戶名和密碼時,BasicAuthenticationFilter通過從HttpServletRequest中提取用戶名和密碼來創(chuàng)建UsernamePasswordAuthenticationToken;
  2. 將UsernamePasswordAuthenticationToken傳遞到AuthenticationManager進行身份驗證(這邊的AuthenticationManager的認(rèn)證邏輯與Form Login相同);
  3. 認(rèn)證失敗會做一些清理動作;
  4. 認(rèn)證成功,將Authentication存儲到SecurityContextHolder、RememberMe相關(guān)處理、調(diào)用FilterChain.doFilter(request,response)繼續(xù)請求邏輯。
  • Digest Authentication:摘要式身份驗證;不建議在現(xiàn)代應(yīng)用程序中使用摘要式身份驗證,因為它不安全。 它必須以純文本,加密或MD5格式存儲密碼,這些存儲格式都被認(rèn)為是不安全的。不支持的單向自適應(yīng)密碼哈希(即bCrypt,PBKDF2,SCrypt等)存儲憑據(jù)。

Remember-Me認(rèn)證

Remember-Me(記住我),主要用于在一段很長的時間內(nèi)(通常15天),用戶只需要登錄一次,就無需再登錄了(前提是用戶名、密碼、秘鑰不變的情況)。

原理:當(dāng)用戶登錄成功時,服務(wù)端會向瀏覽器額外發(fā)送一個cookie(name = remember-me, value = token值),之后的請求都會攜帶這個cookie,當(dāng)用戶session失效時(比如2小時過后),該cookie攜帶到服務(wù)端觸發(fā)自動登錄。

當(dāng)然,Remember-Me會存在一些安全問題,Remember-Me的token可以被用戶代理捕獲到,可以輕松通過該token去修改密碼。因此在一些安全性重要的應(yīng)用上面,不建議開啟Remember-Me。

存儲機制
  • In-Memory:內(nèi)存存儲;Spring Security的InMemoryUserDetailsManager實現(xiàn)了UserDetailsS??ervice,用來管理內(nèi)存中的用戶名/密碼。
  • JDBC:數(shù)據(jù)庫存儲;使用JdbcUserDetailsManager基于JDBC的用戶名/密碼身份驗證。
  • 自定義存儲:使用UserDetailsService可自定義存儲方式;例如:
// CustomUserDetailsS??ervice是UserDetailsS??ervice的實現(xiàn)類
@Bean
CustomUserDetailsService customUserDetailsService() {
    return new CustomUserDetailsService();
}
  • LDAP:LDAP存儲,有興趣可以自行查閱官方文檔;

授權(quán)原理分析(Servlet)

FilterSecurityInterceptor授權(quán)

FilterSecurityInterceptor為HttpServletRequests提供授權(quán),它作為安全篩選器之一插入到FilterChainProxy中(除此之外,Spring Security支持服務(wù)層方法授權(quán)還有域?qū)ο笫跈?quán))。


image.png
  1. FilterSecurityInterceptor可以從SecurityContextHolder獲取Authentication;
  2. FilterSecurityInterceptor將HttpServletRequest、HttpServletResponse、FilterChain包裝成FilterInvocation對象,調(diào)用父類AbstractSecurityInterceptor.beforeInvocation(),進入前置處理階段;
  3. AbstractSecurityInterceptor從SecurityMetadataSource獲取配置信息
    ConfigAttribute(例如:hasRole('ROLE_USER'));調(diào)用AbstractSecurityInterceptor.authenticateIfRequired()執(zhí)行認(rèn)證相關(guān)邏輯;
  4. 調(diào)用AccessDecisionManager.decide()方法,進行訪問決策處理,該方法將決策委托給AccessDecisionVoter訪問決策投票器,進行投票處理,AccessDecisionManager將投票的結(jié)果進行整合;
  5. 如果AccessDecisionManager決策被拒絕,則拋出AccessDeniedException,ExceptionTranslationFilter捕獲到這個異常,并交給AuthenticationEntryPoint進行相應(yīng)的處理,例如跳轉(zhuǎn)登錄頁、返回403狀態(tài)等;
  6. 如果AccessDecisionManager決策成功,則方法正常調(diào)用chain.doFilter();
  7. 方法正常調(diào)用完成后,通過AbstractSecurityInterceptor.afterInvocation()進入后置處理階段(某些應(yīng)用程序需要修改實際返回的對象);

Authorities權(quán)限列表

image.png

回顧下前面學(xué)到的知識,用戶登錄認(rèn)證成功后,會為當(dāng)前用戶生成一個Authentication對象,該對象包含了Principal、Credentials和Authorities;
該Authorities由GrantedAuthority(默認(rèn)實現(xiàn):SimpleGrantedAuthority)集合組成,GrantedAuthority接口只有一個方法,如下:

String getAuthority();

一般情況下GrantedAuthority由String表示,如果GrantedAuthority無法精確地表示為String,則GrantedAuthority被視為“復(fù)雜”,并且getAuthority()必須返回null。

前置處理階段

剛剛講到Spring Security調(diào)用AbstractSecurityInterceptor.beforeInvocation()進入前置處理階段,該階段的一個重點就是進行訪問決策處理,由AccessDecisionManager相關(guān)實現(xiàn)來完成,AccessDecisionManager接口包含三個方法:

// 決策處理邏輯
void decide(Authentication authentication, Object secureObject,
    Collection<ConfigAttribute> attrs) throws AccessDeniedException;
// 項目啟動校驗配置是否正確
boolean supports(ConfigAttribute attribute);
// 項目啟動校驗配置是否正確
boolean supports(Class clazz);
image.png

如上圖所示,Spring Security提供了三個決策處理器AccessDecisionManager的實現(xiàn)類(AffirmativeBased、ConsensusBased、UnanimousBased),代表三種不同的決策處理器,當(dāng)然也可以自定義決策處理器。決策處理器將決策邏輯委托給多個投票器AccessDecisionVoter(具體實現(xiàn)有:AuthenticatedVoter、RoleVoter、WebExpressionVoter等),接著AccessDecisionManager將投票結(jié)果進行整合,返回拒絕或者成功。

AccessDecisionManager實現(xiàn)類的具體描述如下:

  • AffirmativeBased:只要有一票通過,返回成功;
  • ConsensusBased:通過票數(shù) > 不通過票數(shù),返回成功;如果通過票數(shù) = 不通過票數(shù),這個時候配置allowIfEqualGrantedDeniedDecisions=true,即可返回成功;
  • UnanimousBased:與上面兩個不同的是,UnanimousBased需要輪詢每個ConfigAttribute,然后投票器對每個ConfigAttribute進行投票,只要有一票不通過,則返回失敗。

AccessDecisionVoter通過返回int來表示投票的結(jié)果,有ACCESS_ABSTAIN(0,棄權(quán)),ACCESS_DENIED(-1,不通過)和ACCESS_GRANTED(1,通過),AccessDecisionVoter主要的實現(xiàn)類如下:

  • RoleVoter:角色投票器,最常用的投票器。如果任何ConfigAttribute以前綴ROLE_開頭,它將進行投票,否則投票者將棄權(quán)ACCESS_ABSTAIN,如果存在GrantedAuthority可以返回一個字符串表示形式(通過getAuthority()方法),該字符串表示形式完全等于一個或多個以前綴ROLE_開頭的ConfigAttributes,則它將投票通過ACCESS_GRANTED,否則投票不通過ACCESS_DENIED。
  • AuthenticatedVoter:用來區(qū)分匿名,完全認(rèn)證和記住我的認(rèn)證用戶。 許多站點允許使用“記住我”身份驗證,但是某些資源確要求完全認(rèn)證方式(用戶登錄)才能訪問。
  • WebExpressionVoter:web表達式投票器,基于Spring EL進行解析,例如:hasRole('ROLE_USER')。表達式根對象的基類是SecurityExpressionRoot,提供了Web和方法安全性中都可用的一些常用表達式。詳情參考:https://docs.spring.io/spring-security/site/docs/5.4.1/reference/html5/#el-access

后置處理階段

某些應(yīng)用程序需要一種修改返回的對象的方法,因此Spring Security提供了一個方便的掛鉤AfterInvocationManager,通過AfterInvocationManager來修改返回對象。


image.png

如上圖所示,AfterInvocationManager有一個具體的實現(xiàn)AfterInvocationProviderManager,它輪詢AfterInvocationProvider的列表。 每個AfterInvocationProvider都可以修改返回對象或引發(fā)AccessDeniedException。 實際上,由于前一個提供程序的結(jié)果將傳遞到列表中的下一個,因此多個提供程序可以修改該對象。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內(nèi)容