基于數(shù)據(jù)庫的用戶認(rèn)證實(shí)現(xiàn)SpringBoot3整合SpringSecurity6的過程
寫在前面
上一篇文章中,我們了解了SpringSecurity
怎么基于內(nèi)存進(jìn)行用戶認(rèn)證。但這還遠(yuǎn)遠(yuǎn)不夠,在實(shí)際開發(fā)中。
用戶往往都存在于數(shù)據(jù)庫,所以從這篇文章開始,我們就要開始學(xué)習(xí)基于數(shù)據(jù)庫的用戶認(rèn)證。
一、認(rèn)證流程
其實(shí)基于數(shù)據(jù)庫的用戶認(rèn)證和基于內(nèi)存認(rèn)證大同小異,我們只需要將從內(nèi)存獲取用戶信息,換成從數(shù)據(jù)庫獲取用戶信息即可。
換成代碼就是替換掉InMermoryUserDetailManager
實(shí)現(xiàn)類,自己去實(shí)現(xiàn)UserDetailsService
,從數(shù)據(jù)庫查詢用戶然后返回。
二、SpringBoot3整合數(shù)據(jù)庫
在進(jìn)行認(rèn)證前,我們需要保證SpringBoot
能正常整合數(shù)據(jù)庫,查詢用戶信息。這里我們使用的數(shù)據(jù)庫是MySQL8.0
。
2.1 創(chuàng)建數(shù)據(jù)庫、表、插入數(shù)據(jù)
①創(chuàng)建數(shù)據(jù)庫
我們這里創(chuàng)建一個security-demo
的數(shù)據(jù)庫
-- 創(chuàng)建數(shù)據(jù)庫 CREATE DATABASE `security-demo`; USE `security-demo`;
② 創(chuàng)建用戶
-- 創(chuàng)建用戶表 CREATE TABLE `user`( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -- 主鍵ID `username` VARCHAR(50) DEFAULT NULL , -- 用戶名 `password` VARCHAR(500) DEFAULT NULL, -- 密碼 `enabled` BOOLEAN NOT NULL -- 是否啟用 );
③ 創(chuàng)建唯一索引
在這里一個用戶的用戶名
username
字段肯定是不能重復(fù)的,所以要為username
創(chuàng)建唯一索引,保證username
的唯一
CREATE UNIQUE INDEX `user_username_uindex` ON `user`(`username`);
④ 插入數(shù)據(jù)
為了方便測試,我們默認(rèn)插入幾個用戶。為了安全起見,這里密碼采用
SpringSecurity
默認(rèn)的bcrypt
加密方式。不清楚的小伙可以先不用管,再后面的文章中會詳細(xì)介紹到密碼加密算法
-- 插入用戶數(shù)據(jù)(密碼是 "password" ) INSERT INTO `user` (`username`, `password`, `enabled`) VALUES ('admin', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE), ('xiezhr', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE), ('xiaofan', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE);
2.2 配置Lombok
為了偷懶,我們還引入了Lombok
。 使用Lombok
,可以讓我們避免寫get
、set
、toString
等樣板式代碼??胺Q偷懶神器,解放了雙手。
① 下面例舉了怎么使用Lombok
來偷懶
- 簡化 Getter 和 Setter 方法:在傳統(tǒng)的 Java 開發(fā)中,你經(jīng)常需要為每個類的屬性手動編寫
Getter
和Setter
方法,但是有了Lombok
,你只需要在屬性上加上@Getter
和@Setter
注解,Lombok
就會為你自動生成這些方法。 - 自動生成構(gòu)造函數(shù):通過
@NoArgsConstructor
、@RequiredArgsConstructor
或@AllArgsConstructor
注解,你可以快速生成無參構(gòu)造函數(shù)、帶有必需參數(shù)的構(gòu)造函數(shù)或者帶有全部參數(shù)的構(gòu)造函數(shù)。 - 自動生成 equals 和 hashCode 方法: 通過
@EqualsAndHashCode
注解,Lombok 會根據(jù)類的字段自動生成equals()
和hashCode()
方法,讓你的類更易于比較和使用在集合中。 - 日志記錄更輕松: 使用
@Slf4j
注解,你可以直接在類中使用log
對象,而無需手動創(chuàng)建日志記錄器。 - 簡化異常拋出: 通過
@SneakyThrows
注解,你可以在方法中拋出受檢異常,而無需顯式地在方法上聲明或捕獲它們。 - 數(shù)據(jù)類簡化: 使用
@Data
注解,Lombok 會為你自動生成所有常用方法,如 Getter、Setter、toString()
等,讓你的數(shù)據(jù)類更加簡潔。 - 鏈?zhǔn)秸{(diào)用: 使用
@Builder
注解,Lombok 可以幫你創(chuàng)建一個更優(yōu)雅的構(gòu)建器模式,讓你的對象初始化更加流暢。
② IDEA 中安裝 Lombok
插件
我們需要再IDEA中安裝了
Lombok
插件,才能正式愉快的使用Lombok
。
根據(jù)你的系統(tǒng)依次點(diǎn)擊菜單:
Windows 系統(tǒng):File -> Settings... -> Plugins;
Mac 系統(tǒng):IntelliJ IDEA -> Preferences -> Plugins;
點(diǎn)擊 Marketplace
, 進(jìn)入插件市場, 輸入關(guān)鍵詞 lombok
, 搜索該插件:
③ 引入依賴
在pom.xml文件中添加如下依賴
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> </dependency>
2.3 引入Mybatis Plus
為了方便后續(xù)數(shù)據(jù)庫增刪改查等操作,我們引入MybatisPuls
作為持久層框架。
① Mybatis Plus簡介
有些小伙伴可能還不知道MybatisPuls
,這里簡單介紹一下,知道的小伙伴直接跳過即可。
用白話文說MybatisPuls
是一款操作數(shù)據(jù)庫的框架。它是一個 MyBatis
的增強(qiáng)工具,就像 iPhone
手機(jī)一般都有個 plus
版本一樣,它在 MyBatis
的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生。
MyBatis Plus
的愿景是成為 MyBatis
最好的搭檔,就像魂斗羅中的 1P
、2P
,基友搭配,效率翻倍。
② 引入依賴
為了整合mybatis-plus,我們需要在pom.xml中引入如下依賴
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency>
2.4 引入MySQL依賴
我們這里數(shù)據(jù)庫使用的是MySQL,所以還得引入MySQL相關(guān)依賴
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>
2.5 完整依賴
最終完整依賴如下
<dependencies> <!-- web依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--SpringSecurity 依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.2.10</version> </dependency> <!--lombok依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> </dependency> <!--SpringBoot3整合mybatis-plus 依賴--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency> <!--junit依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--MySQL依賴--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies>
2.6 配置數(shù)據(jù)源
application.yml文件中配置MySQL數(shù)據(jù)源,即mybatis-plus日志
# MySQL數(shù)據(jù)源 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3308/security-demo username: root password: 123456 # MySQL日志 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.7 創(chuàng)建實(shí)體類
package com.xiezhr.securityindbuser.entity; @TableName("user") @Data public class User { @TableId(value = "id", type = IdType.AUTO) private Integer id; @TableField(value = "username") private String username; @TableField(value = "password") private String password; @TableField(value = "enabled") private Boolean enabled; }
@TableName("user")
:mybatis-plus
注解,用來指定數(shù)據(jù)庫表名。這里實(shí)體名稱與數(shù)據(jù)庫表名一致,該注解可省略@Data
:Lombok
注解,用來生成get
、set
方法@TableId(value = "id", type = IdType.AUTO)
:mybatis-plus
注解,用來指定了字段id
為表的主鍵,同時指定主鍵為自增類型@TableField(value = "username")
:mybatis-plus
注解,用來指定字段名。這里實(shí)體類屬性與數(shù)據(jù)庫字段一致,該注解可省略
2.8 Mapper接口
package com.xiezhr.securityindbuser.mapper; @Mapper public interface UserMapper extends BaseMapper<User> { }
- 繼承
BaseMapper
通用類,可以默認(rèn)幫我們實(shí)現(xiàn)基本增刪改查
2.9 Service
① 接口
package com.xiezhr.securityindbuser.service; public interface UserService extends IService<User> { }
② 實(shí)現(xiàn)
package com.xiezhr.securityindbuser.service.impl; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
2.10 Controller
package com.xiezhr.securityindbuser.controller; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/list") public List<User> getUserList(){ return userService.list(); } }
2.11 測試是否正常獲取數(shù)據(jù)
以上小節(jié)中,我們建立了各種類。結(jié)構(gòu)如下
啟動服務(wù),瀏覽器中輸入:http://localhost:8080/user/list 看看是否能查出數(shù)據(jù)庫中用戶數(shù)據(jù)?
至此,我們已經(jīng)成功整合數(shù)據(jù)庫,并且從數(shù)據(jù)庫中查詢出了用戶信息。
接下來,我們要做的就是把認(rèn)證流程從內(nèi)存中獲取用戶信息替換成我們自己實(shí)現(xiàn)從數(shù)據(jù)庫中查詢用戶信息。
三、基于數(shù)據(jù)庫的用戶認(rèn)證
3.1 認(rèn)證流程
通過之前基于內(nèi)存認(rèn)證分析,我們知道。只要實(shí)現(xiàn)UserDetailsService
接口的loadUserByUsername
方法就可以從數(shù)據(jù)庫中獲取用戶信息。
- 程序啟動時:
- 創(chuàng)建
DBUserDetailsManager
類,實(shí)現(xiàn)接口UserDetailsService
接口 - 在應(yīng)用程序中初始化這個類的對象,使springsecurity不再從內(nèi)存中獲取用戶信息,而是通過我們自己實(shí)現(xiàn)類從數(shù)據(jù)庫中查詢用戶信息。
- 創(chuàng)建
- 校驗(yàn)用戶時:
- SpringSecurity自動使用
DBUserDetailsManager
的loadUserByUsername
方法從數(shù)據(jù)庫中
獲取User對象 - 在
UsernamePasswordAuthenticationFilter
過濾器中的attemptAuthentication
方法中將用戶輸入的用戶名密碼和從數(shù)據(jù)庫中獲取到的用戶信息進(jìn)行比較,進(jìn)行用戶認(rèn)證
- SpringSecurity自動使用
3.2 創(chuàng)建DBUserDetailsManager
我們在service包下創(chuàng)建DBUserDetailsManager
來實(shí)現(xiàn)UserDetailsService
接口,替換從內(nèi)存中獲取用戶信息。代碼如下
package com.xiezhr.securityindbuser.service.impl; public class DBUserDetailsManager implements UserDetailsService { @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<User> queryWrapper = new QueryWrapper<User>(); //使用username構(gòu)造查詢條件 QueryWrapper<User> wrapper = queryWrapper.eq("username", username); //由于用戶名不能重復(fù),所以我們使用selectOne查詢用戶信息即可 User user = userMapper.selectOne(wrapper); if (user == null) { //用戶不存在,拋出異常 throw new UsernameNotFoundException(username); } else { //由于現(xiàn)在還沒有權(quán)限信息,所以我們構(gòu)造一個空的權(quán)限信息 Collection< GrantedAuthority> authorities = new ArrayList<>(); return new org.springframework.security.core.userdetails.User( user.getUsername(), // user.getPassword(), user.getEnabled(), true, //用戶賬戶是否沒過期 true, //用戶憑證是否沒過期 true, //用戶是否未被鎖定 authorities //用戶權(quán)限信息 ); } } }
3.3 初始化UserDetailsService
說了一堆理論,那么我們怎么才能讓springsecurity
不從內(nèi)存獲取用戶信息,而是通過上一步創(chuàng)建的DBUserDetailsManager
來查詢用戶信息。
接下來的就比較關(guān)鍵了,我們只需創(chuàng)建一個WebSecurityConfig
,然后創(chuàng)建基于數(shù)據(jù)庫的用戶管理器dbUserDetailsManager
即可
package com.xiezhr.securityindbuser.config; @Configuration //標(biāo)明這個類為配置類,spring應(yīng)用程序一啟動,類中的been 就會被初始化在spring容器中 @EnableWebSecurity //開啟spring security 自定義配置 public class WebSecurityConfig { @Bean public UserDetailsService userDetailsService(){ //創(chuàng)建基于數(shù)據(jù)庫的用戶管理器 DBUserDetailsManager dbUserDetailsManager = new DBUserDetailsManager(); return dbUserDetailsManager; } }
當(dāng)然我們也可以直接在DBUserDetailsManager
類上添加@Component
注解,也能實(shí)現(xiàn)同樣的效果
3.4 測試一下
通過上面的步驟,基于數(shù)據(jù)庫的認(rèn)證基本就完成了。
在整合數(shù)據(jù)庫的時候我們插入了三個用戶信息
下面我們來測試下成果,瀏覽器中輸入:http://localhost:8080/user/list
隨便輸入上面三個用戶中一個,admin/password
xiezhr/password
xiaofan/password
即可正常訪問接口
到此,我們成功完成了基于數(shù)據(jù)庫的用戶認(rèn)證功能,是不是很簡單呢~
到此這篇關(guān)于SpringBoot3整合SpringSecurity6(三)基于數(shù)據(jù)庫的用戶認(rèn)證的文章就介紹到這了,更多相關(guān)SpringBoot3整合SpringSecurity6(三)基于數(shù)據(jù)庫的用戶認(rèn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制功能
- springboot版本升級以及解決springsecurity漏洞的問題
- SpringSecurity在SpringBoot中的自動裝配過程
- SpringBoot集成SpringSecurity安全框架方式
- SpringBoot+SpringSecurity實(shí)現(xiàn)認(rèn)證的流程詳解
- SpringSecurity角色權(quán)限控制(SpringBoot+SpringSecurity+JWT)
- SpringBoot3.0+SpringSecurity6.0+JWT的實(shí)現(xiàn)
- SpringBoot淺析安全管理之基于數(shù)據(jù)庫認(rèn)證
相關(guān)文章
JVM性能調(diào)優(yōu)之運(yùn)行時參數(shù)小結(jié)
jvm是java的運(yùn)行環(huán)境,在jvm中有很多的參數(shù)可以進(jìn)行設(shè)置,本文主要介紹了JVM性能調(diào)優(yōu)之運(yùn)行時參數(shù)小結(jié),具有一定的參考價值,感興趣的可以了解一下2024-04-04解析ConcurrentHashMap: transfer方法源碼分析(難點(diǎn))
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧2021-06-06IDEA “Cannot resolve symbol”爆紅問題解決
最近發(fā)現(xiàn)個問題,IDEA 無法識別同一個 package 里的其他類,將其顯示為紅色,本文就來介紹一下IDEA “Cannot resolve symbol”爆紅問題解決,感興趣的可以了解一下2023-10-10IDEA調(diào)試小技巧之Evaluate調(diào)試工具詳解
這篇文章主要介紹了IDEA調(diào)試小技巧之Evaluate調(diào)試工具,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09