Spring security詳細上手教學(二)用戶管理

Spring security詳細上手教學(二)用戶管理

這章節主要學習:

  • 如何使用UserDetails接口描述用戶
  • 在鑒權流中使用UserDetailsService
  • 自定義的UserDetailsService實現
  • 自定義的UserDetailsManager實現
  • 在鑒權中使用JdbcUserDetialsManager

在Spring security中抽象了許多關于用戶的接口

  • UserDetails,描述了用戶
  • GrantedAuthority,定義用戶可以執行的操作
  • UserDetailsManager,擴展了UserDetails,描述了創建用戶,修改、刪除用戶密碼等等

image-20250425160101340

在用戶管理中,我們使用了UserDetailsService和UserDetailsManager兩個接口。
UserDetailsService 只負責將用戶信息按照用戶名檢索出來。這個功能在用戶身份認證的時候會被用到。UserDetailsManager繼承UserDetailsService ,擴展了增刪改用戶信息的方法。

1. 實現身份驗證

image-20250425100909330

2. 描述用戶

2.1 UserDetails接口

public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
}

如果我們不需要設置用戶過期等邏輯,那么我們可以直接讓isAccountNonExpired返回true即可,同理其他三個接口。
getAuthorities接口返回用戶訪問資源的權限

isXxxx這四個接口,isXxxNon這種方式好像讓人比較困惑,其實這些接口按照身份驗證失敗返回false,相反返回true這樣的邏輯來設定的。

2.2 GrantedAuthority

public interface GrantedAuthority extends Serializable {String getAuthority();
}

需要實現getAuthority方法來返回權限的名稱String。這個接口只有一個方法,所以可以用lambda表達式來實現。
我們還可以使用SimpleGrantedAuthority類來創建。

GrantedAuthority g1 = () -> "READ";
SimpleGrantedAuthority g2 = new SimpleGrantedAuthority("READ");

2.3 UserDetails的最小實現

public class DummyUser implements UserDetails {private final String username;private final String password;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return List.of(() -> "read");}@Overridepublic String getPassword() {return "john";}@Overridepublic String getUsername() {return "12345";}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

2.4 多種用戶信息存儲方式

實際使用中,我們往往會將用戶信息存儲在數據庫中,或者從外部系統調用用戶信息。那么我們就需要將獲取到的用戶信息和UserDetails結合起來。

如下代碼,我們使用jpa的注解將User類的兩種職責結合起來

@Entity
public class User implements UserDetails {@Idprivate int id;private String username;private String password;private String authority;@Overridepublic String getUsername() {return this.username;}@Overridepublic String getPassword() {return this.password;}public String getAuthority() {return this.authority;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return List.of(() -> authority);}// Omitted code
}

我們還可以利用設計模式中的適配器模式進行解耦,使得我們的類既能適配jps的模型也可以適配UserDetails

public class SecurityUserAdaptor implements UserDetails {private final User user;public SecurityUserAdaptor(User user) {this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return List.of(user::getAuthority);}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUsername();}@Overridepublic boolean isAccountNonExpired() {return false;}@Overridepublic boolean isAccountNonLocked() {return false;}@Overridepublic boolean isCredentialsNonExpired() {return false;}@Overridepublic boolean isEnabled() {return false;}
}

3. 如何管理用戶

3.1 理解UserDetailsService約定

public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

身份驗證的事項調用loadUserByUsername獲取用戶信息。

3.2 實現UserDetailsService

public class InmemoryUserDetailsService implements UserDetailsService {private final List<UserDetails> users;public InmemoryUserDetailsService(List<UserDetails> users) {this.users = users;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {return users.stream().filter(user -> user.getUsername().equals(username)).findFirst().orElseThrow(() -> new UsernameNotFoundException("User not found"));}
}

這里自定義了一個用戶list將用戶信息保存在內存中。
loadUserByUsername方法從List中根據用戶名篩選出來用戶信息

3.3 UserDetailsManager擴展UserDetailsService接口

public interface UserDetailsManager extends UserDetailsService {void createUser(UserDetails user);void updateUser(UserDetails user);void deleteUser(String username);void changePassword(String oldPassword, String newPassword);boolean userExists(String username);
}

3.4 JdbcUserDetailsManager

需要先引入依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>

JdbcUserDetailsManager類管理存儲在SQL數據庫中的用戶信息,通過JDBC鏈接數據庫。

@Configuration
public class ProjectConfig {@Beanpublic UserDetailsService userDetailsManager(DataSource dataSource) {String usersByUsernameQuery = "select username, password, enabled [CA] from users where username = ?";String authsByUserQuery = "select username, authority [CA] from spring.authorities where username = ?";var userDetailsManager = new JdbcUserDetailsManager(dataSource);userDetailsManager.setUsersByUsernameQuery(usersByUsernameQuery);userDetailsManager.setAuthoritiesByUsernameQuery(authsByUserQuery);return userDetailsManager;}@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
}

3.5 LdapUserDetailsManager

LDAP沒接觸過,暫時省略

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78718.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78718.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78718.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡安全廠商F5榮登2025 CRN AI 100榜單,釋放AI潛力

近期&#xff0c;網絡安全廠商F5憑借其應用交付和安全技術與前沿的人工智能洞察&#xff0c;成功入選“2025 CRN AI 100 榜單”&#xff0c;并躋身“領導者”之列。這一榮譽的獲得&#xff0c;彰顯了F5在助力企業擁抱人工智能創新的過程中&#xff0c;無需犧牲性能、靈活性或安…

4.RabbitMQ - 延遲消息

RabbitMQ延遲消息 文章目錄 RabbitMQ延遲消息一、延遲消息介紹二、實現2.1 死信交換機2.2 延遲消息插件2.3 取消超時訂單 一、延遲消息介紹 延遲消息&#xff1a;生產者發送消息時指定一個時間&#xff0c;消費者不會立刻收到消息&#xff0c;而是在指定時間后才收到消息 用戶…

5.學習筆記-SpringMVC(P53-P60)

1.響應 &#xff08;1&#xff09;響應頁面 &#xff08;2&#xff09;響應數據&#xff08;異步提交&#xff09;&#xff1a;文本數據、json數據 2.REST風格 (1)REST:表現形式狀態轉換。 (2)傳統風格資源描述形式 3.Restful入門案例 5.基于RESTful頁面數據…

Golang | 搜索表達式

// (( A | B | C ) & D ) | E & (( F | G ) & H )import "strings"// 實例化一個搜索表達式 func NewTermQuery(field, keyword string) *TermQuery {return &TermQuery{Keyword: &Keyword{Field: field, Word: keyword},} }func (tq *TermQuery…

LangChain構建大模型應用之RAG

RAG(Retrieval-augmented Generation 檢索增強生成)是一種結合信息檢索與生成模型的技術,通過動態整合外部知識庫提升大模型輸出的準確性和時效性。其核心思想是在生成答案前,先檢索外部知識庫中的相關信息作為上下文依據,從而突破傳統生成模型的靜態知識邊界。 為什么我們…

Ubuntu 下 Nginx 1.28.0 源碼編譯安裝與 systemd 管理全流程指南

一、環境與依賴準備 為確保編譯順利&#xff0c;我們首先更新系統并安裝必要的編譯工具和庫&#xff1a; sudo apt update sudo apt install -y build-essential \libpcre3 libpcre3-dev \zlib1g zlib1g-dev \libssl-dev \wgetbuild-essential&#xff1a;提供 gcc、make 等基…

第十二章-PHP文件上傳

第十二章-PHP文件上傳 一&#xff0c;文件上傳原理 一、HTTP協議與文件上傳 1. 請求體結構 當表單設置enctype"multipart/form-data"時&#xff0c;瀏覽器會將表單數據編碼為多部分&#xff08;multipart&#xff09;格式。 Boundary分隔符&#xff1a;隨機生成的…

CSS元素動畫篇:基于當前位置的變換動畫(三)

基于當前位置的變換動畫&#xff08;三&#xff09; 前言縮放效果類元素動畫脈沖動畫效果效果預覽代碼實現 橡皮筋動畫效果效果預覽代碼實現 果凍動畫效果效果預覽代碼實現 歡呼動畫效果效果預覽代碼實現 心跳動畫效果效果預覽代碼實現 結語 前言 CSS元素動畫一般分為兩種&…

Redis ssd是什么?Redis 內存空間優化的點都有哪些?embstr 和 row、intset、ziplist分別是什么?

Redis SSD 是什么&#xff1f; Redis SSD 通常指 Redis 使用 SSD&#xff08;固態硬盤&#xff09;作為持久化存儲介質的場景。雖然 Redis 是內存數據庫&#xff08;數據主要駐留內存&#xff09;&#xff0c;但其持久化機制&#xff08;如 RDB 快照和 AOF 日志&#xff09;需…

【藍橋杯】 數字詩意

數字詩意 在詩人的眼中&#xff0c;數字是生活的韻律&#xff0c;也是詩意的表達。 小藍&#xff0c;當代頂級詩人與數學家&#xff0c;被賦予了”數學詩人”的美譽。他擅長將冰冷的數字與抽象的詩意相融合&#xff0c;并用優雅的文字將數學之美展現于紙上。 某日&#xff0…

DHCP 服務器運行流程圖

以常見的 DHCP v4 為例,其完整流程如下: 一、客戶端請求 IP 地址階段 DHCPDiscover:客戶端啟動后,會以廣播的形式發送 DHCPDiscover 報文,目的是在網絡中尋找可用的 DHCP 服務器。該報文中包含客戶端的 MAC 地址等信息,以便服務器能夠識別客戶端。DHCPOffer:網絡中的 D…

一種企業信息查詢系統設計和實現:xujian.tech/cs

一種企業信息查詢系統設計和實現&#xff1a;xujian.tech/cs 背景與定位 企業在對外合作、風控審查或市場調研時&#xff0c;常需快速獲取公開的工商信息。本文介紹一個企業信息搜索引擎&#xff0c;面向普通用戶與開發者&#xff0c;幫助快速定位企業名稱、統一社會信用代碼…

前端面試高頻算法

前端面試高頻算法 1 排序算法&#xff1b;1.1 如何分析一個排序算法1.1.1 執行效率3.1.2 內存消耗1.1.3 穩定性 1.2 冒泡排序&#xff08;Bubble Sort&#xff09;1.3 插入排序&#xff08;Insertion Sort&#xff09;1.4 選擇排序&#xff08;Selection Sort&#xff09;1.5 歸…

C++初階-模板初階

目錄 1.泛型編程 2.函數模板 2.1函數模板概念 2.2實現函數模板 2.3模板的原理 2.4函數模板的實例化 2.4.1隱式實例化 2.4.2顯式初始化 2.5模板參數的匹配原則 3.類模板 3.1類模板定義格式 3.2類模板的實例化 4.總結 1.泛型編程 對廣泛的類型法寫代碼&#xff0c;我…

「Mac暢玩AIGC與多模態02」部署篇01 - 在 Mac 上部署 Ollama + Open WebUI

一、概述 本篇介紹如何在 macOS 環境下本地部署 Ollama 推理服務,并通過 Open WebUI 實現可視化交互界面。該流程無需 CUDA 或專用驅動,適用于 M 系列或 Intel 芯片的 Mac,便于快速測試本地大語言模型能力。 二、部署流程 1. 環境準備 安裝 Homebrew(如尚未安裝):/bin…

JavaScript 中 undefined 和 not defined 的區別

在 JavaScript 的調試過程中&#xff0c;你是否經常看到 undefined 卻不知其來源&#xff1f;是否曾被 ReferenceError: xxx is not defined 的錯誤提示困擾&#xff1f;這兩個看似相似的概念&#xff0c;實際上是 JavaScript 類型系統中最重要的分水嶺。本文將帶你撥開迷霧&am…

django admin AttributeError: ‘UserResorce‘ object has no attribute ‘ID‘

在 Django 中遇到 AttributeError: ‘UserResource’ object has no attribute ‘ID’ 這類錯誤通常是因為你在代碼中嘗試訪問一個不存在的屬性。在你的例子中&#xff0c;錯誤提示表明 UserResource 類中沒有名為 ID 的屬性。這可能是由以下幾個原因造成的&#xff1a; 拼寫錯…

對鴻蒙 Next 系統“成熟論”的深度剖析-優雅草卓伊凡

對鴻蒙 Next 系統“成熟論”的深度剖析-優雅草卓伊凡 在科技飛速發展的當下&#xff0c;鴻蒙 Next 系統無疑成為了眾多科技愛好者與行業人士關注的焦點。今日&#xff0c;卓伊凡便收到這樣一個饒有趣味的問題&#xff1a;鴻蒙 Next 系統究竟需要多長時間才能完全成熟&#xff…

快速上手GO的net/http包,個人學習筆記

更多個人筆記&#xff1a;&#xff08;僅供參考&#xff0c;非盈利&#xff09; gitee&#xff1a; https://gitee.com/harryhack/it_note github&#xff1a; https://github.com/ZHLOVEYY/IT_note 針對GO中net/http包的學習筆記 基礎快速了解 創建簡單的GOHTTP服務 func …

AI-Browser適用于 ChatGPT、Gemini、Claude、DeepSeek、Grok的客戶端開源應用程序,集成了 Monaco 編輯器。

一、軟件介紹 文末提供程序和源碼下載學習 AI-Browser適用于 ChatGPT、Gemini、Claude、DeepSeek、Grok、Felo、Cody、JENOVA、Phind、Perplexity、Genspark 和 Google AI Studio 的客戶端應用程序&#xff0c;集成了 Monaco 編輯器。使用 Electron 構建的強大桌面應用程序&a…