Spring Security 應該是 Spring 全家桶中學習曲線最爲陡峭的幾個模塊之一了,最開始看書學習的時候,在看了幾回還有一些迷糊後就放棄了。html
直到前段時間再次撿起來,此次在網上找了不少資料後,終於對 Spring Security 有了必定的理解,發現,理解起來其實也不是那麼難。前端
這裏即是一個簡單的梳理總結。java
不少人在剛開始學習 Web 應用程序的編寫的時候,應該都使用過下面這種認證方式:web
這樣的認證方式是很簡單的,可是,Spring Security 中的認證流程又未嘗不是這樣的呢?只不過,Spring Security 經過更加統一的抽象接口實現了這樣的認證流程。spring
前面的簡單的認證流程中,是能夠將一些東西抽象出來做爲一個單獨的實體,這些實體均可以在 Spring Security 中找到相應的對象,包括:數據庫
用戶輸入的帳號密碼等信息,這些東西其實就是用戶的認證信息,對應到 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);
}
複製代碼
只憑用戶提供的認證信息每每是不足以用來判斷該用戶是否合法的,所以,咱們一般還須要某種手段來獲取保存在服務端的用戶信息,同時,也須要某種手段來保存用戶信息, 這些對應到 Spring Security 中的話就是 UserDetailsService
和 UserDetails
這兩個對象。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();
}
複製代碼
在擁有了用戶提供的認證信息和保存在服務端的用戶信息後,咱們就須要經過某種方式來比較這兩份信息,而這種來效驗用戶認證信息的對象對應到 Spring Security 中即是 AuthenticationManager
對象了。ide
Authentication authenticate(Authentication authentication)throws AuthenticationException;
複製代碼
而鑑於各類各樣的用戶認證信息和層出不窮的效驗方式,Spring Security 提供了更易於咱們擴展的接口 AuthenticationProvider
和 ProviderManager
這個默認的 AuthenticationManager 實現。 使用時,咱們每每就只須要實現 AuthenticationProvider
就足夠了。學習
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}
複製代碼
能夠看到,AuthenticationProvider 中的方法 authenticate
會返回一個 Authentication
對象,當經過認證後,這個對象每每會保存用戶的詳細信息。
當用戶的認證信息經過效驗後,咱們每每還須要在服務端保存經過的認證信息或生成的令牌,這個保存經過的認證信息的對象在 Spring Security 中就是 SecurityContext
和 SecurityContextHolder
這兩個對象, 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 之間的關係,細節上還有待推敲,所以,仍是留給之後吧 @_@