Spring Security 認證流程梳理

前言

Spring Security 應該是 Spring 全家桶中學習曲線最爲陡峭的幾個模塊之一了,最開始看書學習的時候,在看了幾回還有一些迷糊後就放棄了。html

直到前段時間再次撿起來,此次在網上找了不少資料後,終於對 Spring Security 有了必定的理解,發現,理解起來其實也不是那麼難。前端

這裏即是一個簡單的梳理總結。java

簡單的認證流程

不少人在剛開始學習 Web 應用程序的編寫的時候,應該都使用過下面這種認證方式:web

  1. 前端頁面獲取到用戶的帳號密碼等信息後經過 POST 請求發送給後端
  2. 後端拿到用戶的帳號密碼等信息到數據庫查詢服務端保存的用戶信息
  3. 對比數據庫中的用戶信息和前端傳遞過來的帳號密碼信息
  4. 相同就生成一個 Token 保存到 Seesion 並將 Token 返回給客戶端
  5. 前端保存拿到的 Token 後在後續的請求中攜帶這一 Token 來證實本身的身份

這樣的認證方式是很簡單的,可是,Spring Security 中的認證流程又未嘗不是這樣的呢?只不過,Spring Security 經過更加統一的抽象接口實現了這樣的認證流程。spring

Spring Security

前面的簡單的認證流程中,是能夠將一些東西抽象出來做爲一個單獨的實體,這些實體均可以在 Spring Security 中找到相應的對象,包括:數據庫

  1. 用戶輸入的帳號密碼等信息,這些東西其實就是用戶的認證信息,對應到 Spring Security 中的話就是 Authentication 對象,只不過,Spring Security 中的 Authentication 對象除了保存用戶的認證信息之外, 還能夠用來保存用戶認證成功後從數據庫中拿到的用戶的詳細信息。後端

    public interface Authentication extends Principal, Serializable {
      Collection<? extends GrantedAuthority> getAuthorities();  // 用戶權限
      Object getCredentials();                                  // 用戶認證信息
      Object getDetails();                                      // 用戶詳細信息
      Object getPrincipal();                                    // 用戶身份信息
      boolean isAuthenticated();                                // 當前 Authentication 是否已認證
      void setAuthenticated(boolean isAuthenticated);
    }
    複製代碼
  2. 只憑用戶提供的認證信息每每是不足以用來判斷該用戶是否合法的,所以,咱們一般還須要某種手段來獲取保存在服務端的用戶信息,同時,也須要某種手段來保存用戶信息, 這些對應到 Spring Security 中的話就是 UserDetailsServiceUserDetails 這兩個對象。app

    public interface UserDetailsService {
      UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }
    
    public interface UserDetails extends Serializable {
      Collection<? extends GrantedAuthority> getAuthorities();
      String getPassword();
      String getUsername();
      boolean isAccountNonExpired();
      boolean isAccountNonLocked();
      boolean isCredentialsNonExpired();
      boolean isEnabled();
    }
    複製代碼
  3. 在擁有了用戶提供的認證信息和保存在服務端的用戶信息後,咱們就須要經過某種方式來比較這兩份信息,而這種來效驗用戶認證信息的對象對應到 Spring Security 中即是 AuthenticationManager 對象了。ide

    Authentication authenticate(Authentication authentication)throws AuthenticationException;
    複製代碼

    而鑑於各類各樣的用戶認證信息和層出不窮的效驗方式,Spring Security 提供了更易於咱們擴展的接口 AuthenticationProviderProviderManager 這個默認的 AuthenticationManager 實現。 使用時,咱們每每就只須要實現 AuthenticationProvider 就足夠了。學習

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

    能夠看到,AuthenticationProvider 中的方法 authenticate 會返回一個 Authentication 對象,當經過認證後,這個對象每每會保存用戶的詳細信息。

  4. 當用戶的認證信息經過效驗後,咱們每每還須要在服務端保存經過的認證信息或生成的令牌,這個保存經過的認證信息的對象在 Spring Security 中就是 SecurityContextSecurityContextHolder 這兩個對象, SecurityContext 保存已經過認證的 Authentication 對象,SecurityContextHolder 保存 SecurityContext 到當前線程的上下文,方便咱們的使用。

    public interface SecurityContext extends Serializable {
      Authentication getAuthentication();
      void setAuthentication(Authentication authentication);
    }
    
    public class SecurityContextHolder {
      public static SecurityContext getContext();
      public void SecurityContext setContext();
    }
    複製代碼

    Spring Security 是基於 Filter 來實現的,而每一個請求每每也會分配一個線程,所以,Spring Security 在請求到達具體的處理邏輯以前,就能夠在 Filter 中完成用戶信息的認證,生成 SecurityContext 方面後續的使用。

這裏在附上一張來源於 Spring Security(一) —— Architecture Overview | 芋道源碼 —— 純源碼解析博客 的一張圖,很好的解釋了上述對象之間的關係:

能夠看到,雖然 Spring Security 看似很複雜,可是其核心思想和之前那種簡單的認證流程依然是同樣的。只不過,Spring Security 將其中的關鍵部分抽象了處理,又提供了相應的擴展接口。

咱們在使用時,即可以實現本身的 UserDetailsService 和 UserDetails 來獲取保存用戶信息,實現本身的 Authentication 來保存特定的用戶認證信息, 實現本身的 AuthenticationProvider 使用本身的 UserDetailsService 和 Authentication 來對用戶認證信息進行效驗。

固然了,Spring Security 還存在更多的功能,可是,在對基本流程有了必定的理解後,後續的內容也就可以更加容易的進行學習了。

結語

其實除了 Spring Security 之外還看了一下 Spring Security OAuth2 和 Spring Security JWT,原本感受能夠和這篇博客一塊兒總結了,可是寫着寫着才發現,臥槽,Spring Security 部分的思路那麼清晰, 怎麼到了 Spring Security OAuth2 後就變得斷斷續續的。

而後才發信,只是大體的理清了 Spring Security 和 Spring Security OAuth2 之間的關係,細節上還有待推敲,所以,仍是留給之後吧 @_@

參考連接

相關文章
相關標籤/搜索