Spring Security自定義身份認證

盡管項目啟動時,Spring Security會提供了默認的用戶信息,可以快速認證和啟動,但大多數應用程序都希望使用自定義的用戶認證。對于自定義用戶認證,Spring Security提供了多種認證方式,常用的有In-Memory Authentication(內存身份認證)、JDBC Authentication(JDBC身份認證)和UserDetailsService(身份詳情服務)。下面對Spring Security的這三種自定義身份認證進行詳細講解。

1.內存身份認證

以內存身份認證時,需要在Spring Security的相關組件中進行指定當前認證方式為內存身份認證。Spring Security 5.7.1開始Spring Security將WebSecurityConfigurerAdapter類標注為過時,推薦直接聲明配置類,在配置類中直接定義組件的信息。 本書使用Spring Boot 2.7.6,其對應的Spring Security版本為5.7.5。自定義內存身份認證時,可以通過InMemoryUserDetailsManager類實現,InMemoryUserDetailsManager是UserDetailsService的一個實現類,方便在內存中創建一個用戶。對此,只需 在自定義配置類中創建InMemoryUserDetailsManager實例,在該實例中指定該實例的認證信息,并存入在Spring容器中即可。

(1)創建配置類

創建一個配置類WebSecurityConfig,在該類中創建UserDetailsService類型的InMemoryUserDetailsManager實例對象交由Spring容器管理

@Configuration
public  class  WebSecurityConfig {
@Bean
public  UserDetailsService userDetailsService() {
InMemoryUserDetailsManager users = new  InMemoryUserDetailsManager();
users.createUser(User.withUsername("zhangsan")
.password("{noop}1234")
.roles("ADMIN")
.build());
return  users;
}
}

進行自定義用戶認證時,需要注意以下幾個問題。

提交認證時會對輸入的密碼使用密碼編譯器進行加密并與正確的密碼進行校驗。如果不想要對輸入的密碼進行加密,需要在密碼前對使用{noop}進行標注。

從Spring Security 5開始,自定義用戶認證如果沒有設置密碼編碼器,也沒有在密碼前使用{noop}進行標注,會認證失敗。

自定義用戶認證時,可以定義用戶角色roles,也可以定義用戶權限authorities,在進行賦值時,權限通常是在角色值的基礎上添加“ROLE_”前綴。

自定義用戶認證時,可以為某個用戶一次指定多個角色或權限。

(2)驗證內存身份認證

啟動項目后,查看控制臺輸出的信息,發現沒有默認安全管理時隨機生成了密碼。

在瀏覽器訪問項目首頁“http://localhost:8080/”。

2.JDBC身份認證

JDBC身份認證是通過JDBC連接數據庫,基于數據庫中已有的用戶信息進行身份認證,這樣避免了內存身份認證的弊端,可以實現對系統已注冊的用戶進行身份認證。JdbcUserDetailsManager是Spring Security內置的UserDetailsService的實現類,使用JdbcUserDetailsManager可以通過JDBC將數據庫和Spring Security連接起來。下面對JDBC身份認證方式進行講解。

(1)數據準備

使用之前創建的名為springbootdata的數據庫,在該數據庫中創建三個表user、priv和user_priv,并預先插入幾條測試數據。準備數據的SQL語句如下。?

#選擇使用數據庫
USEspringbootdata;
#創建表user并插入相關數據
DROPTABLEIFEXISTS`user`;
CREATETABLE`user`(
`id`int(20)NOTNULLAUTO_INCREMENT,
`username`varchar(200)DEFAULTNULL,
`password`varchar(200)DEFAULTNULL,
`valid`tinyint(1)NOTNULLDEFAULT1,
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=4DEFAULTCHARSET=utf8;
INSERTINTO`user`VALUES('1','zhangsan',
'$2a$10$7fWqX7Y010pMnyym/AHZX.3chIbnPZbj3N/iqcG4APCF.hC6CMh5a','1');
INSERTINTO`user`VALUES('2','lisi',
'$2a$10$7fWqX7Y010pMnyym/AHZX.3chIbnPZbj3N/iqcG4APCF.hC6CMh5a','1');
#創建表priv并插入相關數據
DROPTABLEIFEXISTS`priv`;
CREATETABLE`priv`(
`id`int(20)NOTNULLAUTO_INCREMENT,
`authority`varchar(20)DEFAULTNULL,
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=3DEFAULTCHARSET=utf8;
INSERTINTO`priv`VALUES('1','ROLE_COMMON');
INSERTINTO`priv`VALUES('2','ROLE_ADMIN');
#創建表user_priv并插入相關數據
DROPTABLEIFEXISTS`user_priv`;
CREATETABLE`user_priv`(
`id`int(20)NOTNULLAUTO_INCREMENT,
`user_id`int(20)DEFAULTNULL,
`priv_id`int(20)DEFAULTNULL,
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=5DEFAULTCHARSET=utf8;
INSERTINTO`user_priv`VALUES('1','1','1');
INSERTINTO`user_priv`VALUES('2','2','2');

?(2)配置依賴

添加JDBC的啟動器依賴。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

(3)設置配置信息

設置數據庫連接的相關配置信息

(4)修改配置類

修改WebSecurityConfig配置類userDetailsService()方法,將該方法創建的實例對象修改為JdbcUserDetailsManager

@Configuration
public  class  WebSecurityConfig {
@Autowired
private  DataSource dataSource;
@Bean
public  PasswordEncoder passwordEncoder() {
return  new  BCryptPasswordEncoder();
}
@Bean
public  UserDetailsService userDetailsService() {
String userSQL ="SELECT username,password, valid " +
"FROM user WHERE username = ?";
String authoritySQL="SELECT u.username,p.authority " +
"FROM user u,priv p,user_priv up " +
"WHERE up.user_id=u.id AND up.priv_id=p.id and u.username =?";
JdbcUserDetailsManager users = new  JdbcUserDetailsManager();
users.setDataSource(dataSource);
users.setUsersByUsernameQuery(userSQL);
users.setAuthoritiesByUsernameQuery(authoritySQL);
return  users;
}
}

(5)效果測試

重啟項目進行效果測試

3.自定義UserDetailsService身份認證

使用InMemoryUserDetailsManager和JdbcUserDetailsManager進行身份認證時,其真正的認證邏輯都在UserDetailsService接口重寫的loadUserByUsername()方法中。對于一個完善的項目來說,通常會實現用戶信息查詢服務,對此可以自定義一個UserDetailsService實現類,重寫該接口的loadUserByUsername()方法,在該方法中查詢用戶信息,將查詢到的用戶信息填充到UserDetails對象返回,以實現用戶的身份認證。下面通過案例對自定義UserDetailsService進行身份驗證的實現進行演示 。

(1)創建實體類

在子包entity下創建用戶實體類UserDto和權限實體類Privilege

public  class  UserDto {
private  Integer id; //用戶編號
private  String username; //用戶名稱
private  String password; //密碼
private  Integer valid; //是否合法public  Integer getId() {
return  id;
}public  void  setId(Integer id) {
this .id = id;
}public  String getUsername() {
return  username;
}public  void  setUsername(String username) {
this .username = username;
}public  String getPassword() {
return  password;
}public  void  setPassword(String password) {
this .password = password;
}public  Integer getValid() {
return  valid;
}public  void  setValid(Integer valid) {
this .valid = valid;
}
}
public  class  Privilege {
private  Integer id; //編號
private  String authority; //權限public  Integer getId() {
return  id;
}public  void  setId(Integer id) {
this .id = id;
}public  String getAuthority() {
return  authority;
}public  void  setAuthority(String authority) {
this .authority = authority;
}
}

?(2)創建用戶持久層接口

在dao子包下創建用戶持久層接口,在接口中定義查詢用戶及角色信息的方法

@Repository
public  class  UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
//根據賬號查詢用戶信息
public  UserDto getUserByUsername(String username){
String sql = "SELECT * FROM user WHERE username = ?";
//連接數據庫查詢用戶
List<UserDto> list = jdbcTemplate.query(sql, new  BeanPropertyRowMapper<>(UserDto.class ),username);
if (list !=null && list.size()==1){
return  list.get(0);
}
return  null;
}
//根據用戶id查詢用戶權限
public  List<String> findPrivilegesByUserId(Integer userId){
String sql = "SELECT u.username,p.authority " +
"FROM user u,priv p,user_priv up " +
"WHERE up.user_id=u.id AND up.priv_id=p.id and u.id =?";
List<Privilege> list = jdbcTemplate.query(sql, new  BeanPropertyRowMapper<>(Privilege.class ), userId);
List<String> privileges = new  ArrayList<>();
list.forEach(p -> privileges.add(p.getAuthority()));
return  privileges;
}
}

(3)封裝用戶認證信息

在service子包下創建UserDetailsServiceImpl類,該類實現UserDetailsService接口,并在重寫的loadUserByUsername()方法中封裝用戶認證信息

@Service
public  class  UserDetailsServiceImpl implements  UserDetailsService {
@Autowired
UserDao userDao;
//根據用戶名查詢用戶信息
@Override
public  UserDetails loadUserByUsername(String username) throws  UsernameNotFoundException {
//連接數據庫根據賬號查詢用戶信息
UserDto userDto = userDao.getUserByUsername(username);
if (userDto == null){
//如果用戶查不到,返回null,會拋出異常
return  null;
}
//根據用戶的id查詢用戶的權限
List<String> privileges = userDao.findPrivilegesByUserId(userDto.getId());
//將privileges轉成數組
String[] privilegeArray = new  String[privileges.size()];
privileges.toArray(privilegeArray);
UserDetails userDetails = User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities(privilegeArray).build();
return  userDetails;
}
}

(4)效果測試

將userDetailsService()方法進行注釋,使用自定義UserDetailsService身份認證。

重啟項目進行效果測試。

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

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

相關文章

在亞馬遜云服務器上部署WordPress服務

在亞馬遜云服務器上部署WordPress服務第一步&#xff1a;創建EC2實例第二步&#xff1a;初始設置與安裝第三步&#xff1a;配置MySQL與WordPress第四步&#xff1a;配置Apache與WordPress第五步&#xff1a;訪問WordPress第六步&#xff1a;測試數據庫連接第七步&#xff1a;使…

Web3.0的認知補充(去中心化)

涉及開發技術&#xff1a; Vue Web3.js Solidity 基本認知 Web3.0含義&#xff1a; 新一代互聯網思想&#xff1a;去中心化及用戶為中心的互聯網 數據&#xff1a;可讀可寫可授權 核心技術&#xff1a;區塊鏈、NFT 應用&#xff1a;互聯網上應用 NFT &…

如何修復寶可夢時時刻刻冒險無法正常工作

寶可夢的時時刻刻冒險模式是一項強大的功能&#xff0c;即使應用程序關閉&#xff0c;它也能追蹤你的步行距離。它的工作原理是將你的步數與 iOS 上的 Apple Health 或 Android 上的 Google Fit 同步。它對于孵化寶可夢蛋和賺取好友糖果至關重要&#xff0c;但一旦它停止工作&a…

redis常用集合操作命令

在 Redis 的命令行界面&#xff08;redis-cli&#xff09;中&#xff0c; Redis 的集合&#xff08;Set&#xff09;是無序的&#xff0c;且集合中的元素是唯一的。Redis 本身沒有直接提供獲取集合中某個特定屬性的命令&#xff0c;因為集合中的元素是簡單的值&#xff0c;而不…

初識數據結構——二叉樹從基礎概念到實踐應用

數據結構專欄 ?(click) 初識二叉樹&#xff1a;從基礎概念到實踐應用&#x1f333; 一、樹型結構基礎 1.1 樹的基本概念 樹是一種非線性的數據結構&#xff0c;由n(n>0)個有限節點組成一個具有層次關系的集合。它看起來像一棵倒掛的樹&#xff0c;根朝上而葉朝下。 關鍵特…

駝峰命名法(Camel Case)與匈牙利命名法(Hungarian Notation)詳解

駝峰命名法&#xff08;Camel Case&#xff09;與匈牙利命名法&#xff08;Hungarian Notation&#xff09;詳解及對比? ?1. 駝峰命名法&#xff08;Camel Case&#xff09;? ?定義? 駝峰命名法&#xff08;Camel Case&#xff09;是一種變量、函數、類等標識符的命名方…

keil 中優化等級的bug

一&#xff0c;問題描述 程序中代碼有的執行&#xff0c;有的不執行&#xff0c;仔細研究&#xff0c;查詢人工智能。 程序中printf打印后面的代碼不執行&#xff0c; 然后過幾十個函數又開始正常了。 二.分析問題 跳過函數一般又判斷和Goto等語句&#xff0c;其它的溢出和錯誤…

織夢dedecms網站如何修改上一篇下一篇的標題字數

一般情況下&#xff0c;如果你的上一篇和下一篇是2行布局就不需要限制標題的字數了&#xff0c;如果你要一行布局上一篇和下一篇標題過長就會打亂網頁布局&#xff0c;那么限制上一篇和下一篇的標題字數是需要的&#xff0c;避免頁面看起來雜亂不堪。 織夢dedecms網站如何修改…

信創系統 sudoers 權限配置實戰!從小白到高手

好文鏈接&#xff1a;實戰&#xff01;銀河麒麟 KYSEC 安全中心執行控制高級配置指南 Hello&#xff0c;大家好啊&#xff01;今天給大家帶來一篇關于信創終端操作系統中 sudoers 文件詳解的實用文章&#xff01;在 Linux 系統中&#xff0c;sudo 是一項非常重要的權限控制機制…

《明解C語言入門篇》讀書筆記四

目錄 第四章&#xff1a;程序的循環控制 第一節&#xff1a;do語句 do語句 復合語句&#xff08;程序塊&#xff09;中的聲明 讀取一定范圍內的值 邏輯非運算符 德摩根定律 德摩根定律 求多個整數的和及平均值 復合賦值運算符 后置遞增運算符和后置遞減運算符 練習…

vite+vue2+elementui構建之 vite.config.js

webpack版本太低&#xff0c;構建依賴太多&#xff0c;頭大。 各種查閱資料&#xff0c;弄了一份直通構建vite構建elementUi核心文件&#xff0c; 構建基于開源若依vue2vue3版本改造&#xff0c;感謝開源&#xff0c;感謝若依。 package.json 地址 vitevue2elementui構建之…

超參數詳解:從基礎概念到優化策略的全面指南

摘要 本文深入解析機器學習中超參數的核心概念&#xff0c;詳細對比參數與超參數的本質區別&#xff0c;系統介紹學習率、隱含層數量等常見超參數類型&#xff0c;以及網格搜索、貝葉斯優化等主流尋優方法。結合超參數搜索的標準流程&#xff0c;通過具體案例演示如何高效調整…

計算機視覺與深度學習 | LSTM原理及與卡爾曼濾波的融合

長短期記憶網絡(LSTM)是一種特殊的循環神經網絡(RNN),旨在解決傳統RNN在處理長序列數據時出現的梯度消失和梯度爆炸問題。以下為你詳細介紹其基本原理: 核心思想:LSTM的核心思想是引入記憶單元和門控機制來控制信息的流動,從而解決傳統RNN的梯度消失問題。記憶單元類似…

EXCEL常用函數公式和VBA匯總第二篇

系列文章目錄 文章目錄 系列文章目錄前言一、excel公式應用1.rand函數2.rand函數隨機排序3.rand函數提取數據4.correl函數5.SUBSTITUTE函數6.MAX組合函數7.分析下班時間8.柏拉圖自動排序 總結 前言 一、excel公式應用 1.rand函數 用excel生成1-5的隨機數字&#xff0c;其中對…

iOS 類與對象底層原理

iOS 類與對象底層原理 文章目錄 iOS 類與對象底層原理探索對象本質objc_setProperty 源碼cls與類的關聯原理聯合體isa的類型isa_t 原理探索initIsa方法通過setClass方法中的shiftcls來驗證綁定的一個流程通過 isa & ISA_MSAK通過object_getClass通過位運算 類&類的結構…

浮點數:IEEE 754標準

IEEE 754 標準是一種由電氣和電子工程師協會&#xff08;IEEE&#xff09;制定的浮點數表示的標準&#xff0c;廣泛應用于計算機系統中&#xff0c;下面是詳細介紹&#xff1a; 歷史背景 在 IEEE 754 標準出現之前&#xff0c;不同的計算機系統采用各自的浮點數表示方法&…

centos7部署k8s集群

環境準備 服務器三臺 10.0.0.70master 10.0.0.71worker1 10.0.0.72worker2 配置yum源&#xff08;集群機器執行&#xff09; wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 安裝常用軟件 yum -y install lrzsz vim net-tools關閉f…

第三方軟件檢測報告:熱門辦公軟件評估及功能表現如何?

第三方軟件檢測報告是重要文件。它用于對軟件做專業評估。能反映軟件各項性能。能反映軟件安全性等指標。該報告為軟件使用者提供客觀參考。該報告為軟件開發者提供客觀參考。有助于發現問題。還能推動軟件改進。 檢測概述 本次檢測針對一款熱門辦公軟件。采用了多種先進技術…

Linux:41線程控制lesson29

1.線程的優點&#xff1a; ? 創建?個新線程的代價要?創建?個新進程?得多 創建好線程只要調度就好了 ? 與進程之間的切換相?&#xff0c;線程之間的切換需要操作系統做的?作要少很多 為什么&#xff1f; ? 最主要的區別是線程的切換虛擬內存空間依然是相同的&#x…

【MCP】從一個天氣查詢服務帶你了解MCP

1. 前言 這篇文章將通過一個集成高德天氣查詢的 MCP Server 用例&#xff0c;帶你上手開發自己的 MCP Server ,文章將通過以下三種方式&#xff08;自己編寫 Client 端代碼&#xff0c;使用 mcp-cli 自帶頁面&#xff0c;集成到 Claude 桌面版等&#xff09;帶你測試自己的 MC…