Spring Security 的作為守門員,其兩大功能:認證(Authentication) 和 授權(authorization)
學而思:
- Spring Security 是如何對用户進行管理的?
初始化項目並啓動
初始化一個 Spring Boot 項目並編寫一個接口,在沒有引入 Spring Security 依賴時,接口是能夠能正常訪問的。
@RestController
@RequestMapping("/user")
public class UmsAdminController {
@GetMapping("/details")
public Object userInfos() {
return "用户詳情";
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
在引入依賴後,再次請求接口 http://localhost:8080/user/details ,頁面跳轉至了登錄頁面。
用户默認名為 user , 默認密碼是每次啓動應用時隨機生成的,啓動應用時,顯示在了控制枱中。
UserDetailsManager
明明什麼都沒幹,只是引入安全的框架,為什麼請求接口就被攔截?
這就與 Spring Security 的機制有關,Spring Security 採用了”默認拒絕“ 的安全策略。意思是資源默認對未認證授權用户禁止訪問。為需要開放的資源進行屬性配置,而不是默認對資源進行開放,這被認為是一種良好的安全做法。
在請求接口前,Spring Security 採用了過濾器對接口進行攔截認證(過濾器是Security 的核心部分,這個之後再詳述)。認證過程中用到 UserDetailsManager ,也就是本章的主角。
UserDetailsManager 是管理用户的接口,繼承了 UserDetailsService 接口,UserDetailsService 提供了加載用户詳細信息(UserDetails)的方法(loadUserByUsername) 。
- UserDetails: 用户詳細信息的接口,對用户的抽象,提供了獲取用户名和密碼等方法
- UserDetailsService:提供了一個加載用户的方法,該方法根據用户名從存儲(內存、數據庫等)中查詢出用户對象(UserDetails),認證過程最終就是通過調用該方法,來認證用户。
- UserDetailsManager:在 UserDetailsService 基礎上增加了 增刪改等功能,實現了對用户的管理。
兩個實現類
在Spring Security 中 ,UserDetailsManager 有兩個實現類,如下圖:
- InMemoryUserDetailsManager:基於內存的用户管理器,項目初始化時默認使用,不能滿足業務需求
- JdbcUserDetailsManager:基於數據庫的用户管理器,更符合真實業務的需求
InMemoryUserDetailsManager
先來探索 InMemoryUserDetailsManager 在Security 中是如何構建的。
在 Spring Boot 中有一個自動配置類 UserDetailsServiceAutoConfiguration 。向Ioc 容器中注入了 InMemoryUserDetailsManager 對象。
在 構建 InMemoryUserDetailsManager 對象的同時,向其注入了一個 User對象(UserDetails 的實現類),並把一個靜態類User 的 name 和 經過加工的 password1 作為 用户名和密碼。
這正好對應了 前面登錄時所需的用户名和密碼。
但是這樣的用户管理器很難滿足真實業務需求,真實的用户數據存在於數據庫中,因此可以重新構建 UserDetailsManager 的實現類 ,對功能進行擴展。
比如下面的 JdbcUserDetailsManager 。
JdbcUserDetailsManager
未完待續。。。
- Spring Security 提供了各種加密策略,密碼前面需要添加{【加密類型】},例如:{noop}123, 表示沒有加密。 ↩