博客 / 詳情

返回

源碼剖析:用户信息的管理者-UserDetailsManager

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 ,頁面跳轉至了登錄頁面。

image-20221014152633274

用户默認名為 user , 默認密碼是每次啓動應用時隨機生成的,啓動應用時,顯示在了控制枱中。

image-20221014152736895

UserDetailsManager

明明什麼都沒幹,只是引入安全的框架,為什麼請求接口就被攔截?

這就與 Spring Security 的機制有關,Spring Security 採用了”默認拒絕“ 的安全策略。意思是資源默認對未認證授權用户禁止訪問。為需要開放的資源進行屬性配置,而不是默認對資源進行開放,這被認為是一種良好的安全做法。

在請求接口前,Spring Security 採用了過濾器對接口進行攔截認證(過濾器是Security 的核心部分,這個之後再詳述)。認證過程中用到 UserDetailsManager ,也就是本章的主角。

UserDetailsManager 是管理用户的接口,繼承了 UserDetailsService 接口,UserDetailsService 提供了加載用户詳細信息(UserDetails)的方法(loadUserByUsername) 。

  • UserDetails: 用户詳細信息的接口,對用户的抽象,提供了獲取用户名和密碼等方法
  • UserDetailsService:提供了一個加載用户的方法,該方法根據用户名從存儲(內存、數據庫等)中查詢出用户對象(UserDetails),認證過程最終就是通過調用該方法,來認證用户。
  • UserDetailsManager:在 UserDetailsService 基礎上增加了 增刪改等功能,實現了對用户的管理。

image-20221014160843027

兩個實現類

在Spring Security 中 ,UserDetailsManager 有兩個實現類,如下圖:

  • InMemoryUserDetailsManager:基於內存的用户管理器,項目初始化時默認使用,不能滿足業務需求
  • JdbcUserDetailsManager:基於數據庫的用户管理器,更符合真實業務的需求

image-20221014160754968

InMemoryUserDetailsManager

先來探索 InMemoryUserDetailsManager 在Security 中是如何構建的。

在 Spring Boot 中有一個自動配置類 UserDetailsServiceAutoConfiguration 。向Ioc 容器中注入了 InMemoryUserDetailsManager 對象。

image-20221014164154494

在 構建 InMemoryUserDetailsManager 對象的同時,向其注入了一個 User對象(UserDetails 的實現類),並把一個靜態類User 的 name 和 經過加工的 password1 作為 用户名和密碼。

image-20221014165121467

這正好對應了 前面登錄時所需的用户名和密碼。

但是這樣的用户管理器很難滿足真實業務需求,真實的用户數據存在於數據庫中,因此可以重新構建 UserDetailsManager 的實現類 ,對功能進行擴展。

比如下面的 JdbcUserDetailsManager 。

JdbcUserDetailsManager

未完待續。。。


  1. Spring Security 提供了各種加密策略,密碼前面需要添加{【加密類型】},例如:{noop}123, 表示沒有加密。 ↩
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.