spring security架構(一)

安全歸根節點須要解決兩個問題:java

  • 鑑權(authentication)--我是誰?
  • 受權(authorization)--容許我作什麼?

後者有些時候也被人們叫作「訪問控制」(access control)。spring security 是一個將鑑權和受權分開的安全框架。包含策略,同時提供對二者的擴展能力。spring

Authencation Architecture

下圖描繪了spring security在鑑權處理流程中涉及到的類和過濾器。數據庫

  1.  外部的http請求訪問內部受保護的Resful API以前,須要通過一系列的安全過濾器。這些被spring security設定的過濾器,用於鑑權和受權的目的。當用戶的鑑權請求從外部進入時,將通過這條過濾器鏈,基於鑑權機制和模型,找到相應的Authentication Filter。好比說:
    • HTTP Basic authentication request 通過「過濾鏈」,直到它到達BasicAuthenticationFilter 過濾器進行處理。
    • HTTP Digest authentication request 通過「過濾鏈」,直到它到達DigestAuthenticationFilter 過濾器進行處理。
    • login form authentication request 通過「過濾鏈」,直到它到達UsernamePasswordAuthenticationFilter過濾器進行處理。
    • x509 authentication request 通過「過濾鏈」,直到它到達X509AuthenticationFilter 過濾器進行處理。
  2. 一旦鑑權請求被相應的Authentication Filter接收,該過濾器將會從接收的請求中提取出用戶名和密碼,基於這些用戶信息,建立一個  UsernamePasswordAuthenticationToken 對象,注意,該類實現了 Authentication 接口。
  3. UsernamePasswordAuthenticationToken  對象建立成功後,被用來做爲 AuthenticationManager 中 authenticate() 方法的入參。 AuthenticationManager 僅僅是一個接口:
    public interface AuthenticationManager{
      Authentication authenticate(Authentication authentication)throws AuthenticationException;
    }
    

    實際實現類是 ProviderManager 。該實現類包含了一系列配置的 AuthenticationProvider (s), 這些provider受ProvideManager委託,用於用戶請求的鑑權。安全

  4. 具體到實現細節, ProviderManager 會遍歷每一個AuthenticationProvider,根據傳入的Authentication對象(例如: UsernamePasswordAuthenticationToken )嘗試鑑權用戶。AuthenticationProvider 接口以下所示:springboot

    public interface AuthenticationProvider { 
        Authentication authenticate(Authentication authentication) throws AuthenticationException; 
        boolean supports(Class<?> authentication);
    }
    

    這裏是一些Spring security框架提供的AuthenticationProvider:框架

    • CasAuthenticationProvider
    • JaasAuthenticationProvider
    • DaoAuthenticationProvider
    • OpenIDAuthenticationProvider
    • RememberMeAuthenticationProvider
    • LdapAuthenticationProvider
  5. 有些AuthenticationProvider可能會使用 UserDetailsService ,用於獲取用戶的詳細信息。好比說 DaoAuthenticationProvider 可能須要根據傳入的用戶名從數據庫中獲取該用戶的詳細信息。
    public interface UserDetailsService{
      UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }
    

     

  6.  UserDetailsService 返回 UserDetails 。而 User 是 UserDetails 的具體實現類,固然用戶也能夠自行實現 UserDetails 接口。ide

  7. 同6
  8.  若是用戶鑑權成功,則返回Authentication對象,相比於傳入的未鑑權的對象,這個鑑權後的的對象更「豐滿」,包含了用戶的角色信息spa

    

從上圖能夠看出,鑑權成功的Authentication對象(Fully populated Authentication Object)包含:3d

  authenticated- truecode

  grant authorities list :關聯的角色(角色和權限掛鉤)

  user credentials:用戶憑證(僅僅包含用戶名)

若是鑑權未經過,則拋出異常 AuthenticationException 。該異常屬於運行時異常,不指望用戶經過try/catch去處理,spring security提供了一種通用的方式。即經過AuthenticationEntryPoint 處理:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(unauthorizedHandler);
    }

  9. Authentication is done! 鑑權成功後,AuthenticationManager返回包含完整信息的鑑權對象給相關的Authentication Filter。

  10. 將返回的鑑權對象保存到SecurityContext,用於後續過濾器的使用。好比Authorization Filters   

SecurityContextHolder.getContext().setAuthentication(authentication);

  

 Reference

https://springbootdev.com/2017/08/23/spring-security-authentication-architecture/

相關文章
相關標籤/搜索