SpringSecurity整合MyBatis實現(xiàn)數(shù)據(jù)庫認(rèn)證的詳細(xì)步驟
本章將介紹如何將 MySQL 數(shù)據(jù)庫中的用戶信息接入 Spring Security,告別配置文件中的內(nèi)存用戶。
一、問題切入
第一章中我們通過配置文件指定用戶:
spring:
security:
user:
name: flittly
password: 123456這種方式存在明顯缺陷:
- 用戶信息寫在代碼中,無法動態(tài)管理
- 密碼以明文形式存儲,安全性低
- 生產(chǎn)環(huán)境不應(yīng)使用配置文件明文密碼
- 無法擴(kuò)展更多用戶,無法支持注冊/注銷等功能
我們需要一個可擴(kuò)展的方案,將數(shù)據(jù)庫中的用戶信息加載到 Spring Security 中。
二、解決方案:引入 MyBatis
在 pom.xml 中添加 MyBatis Starter 和 MySQL 驅(qū)動:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>三、配置數(shù)據(jù)源連接
在 application.yml 中配置數(shù)據(jù)庫連接:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_security_demo
username: root
password: 123456
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: cn.edu.nnu.opengms.ss02.entity四、原理闡釋:認(rèn)證流程
4.1 核心接口
Spring Security 的認(rèn)證體系圍繞以下核心接口展開:
| 接口 | 作用 |
|---|---|
| UserDetailsService | 根據(jù)用戶名加載用戶信息 |
| UserDetails | 用戶信息封裝對象 |
| PasswordEncoder | 密碼驗證器 |
| Authentication | 認(rèn)證令牌 |
4.2 認(rèn)證流程詳解
整個認(rèn)證流程涉及多個組件的協(xié)作:
用戶提交登錄表單(用戶名 + 密碼)
↓
UsernamePasswordAuthenticationFilter 攔截請求
↓ 提取用戶名
DaoAuthenticationProvider.getUserDetails(username)
↓ 調(diào)用
UserDetailsService.loadUserByUsername(username)
↓ 調(diào)用 MyBatis Mapper
從數(shù)據(jù)庫查詢用戶信息
↓ 返回
構(gòu)建 UserDetails 對象(含密碼、權(quán)限信息)
↓
PasswordEncoder.matches() 驗證密碼
↓ 匹配成功
Authentication 認(rèn)證成功,創(chuàng)建認(rèn)證令牌
↓
SecurityContextHolder.getContext().setAuthentication()
↓
重定向到成功頁面UserDetailsService 是 Spring Security 認(rèn)證體系的核心接口,負(fù)責(zé)根據(jù)用戶名加載用戶信息。
4.3 密碼編碼器
Spring Security 7.x 要求必須配置密碼編碼器,支持多種編碼方式:
- BCrypt:推薦,單向哈希算法,內(nèi)置隨機(jī)鹽
- Argon2:現(xiàn)代密碼哈希算法
- PBKDF2:基于密鑰推導(dǎo)
- Scrypt:計算密集型算法
BCrypt 是目前最常用的選擇,它具有以下特點(diǎn):
- 單向哈希:無法從哈希值反向推導(dǎo)原始密碼
- 內(nèi)置鹽:每次加密生成不同的哈希值,即使相同密碼也不一樣
- 強(qiáng)度可調(diào):通過 work factor 調(diào)整計算時間
五、代碼實現(xiàn)
5.1 Users 實體類
對應(yīng)數(shù)據(jù)庫中的 users 表:
@Data
public class Users implements Serializable {
private Long id;
private String username;
private String password;
private String email;
private String phone;
private Boolean enabled;
private Date createTime;
private Date updateTime;
}5.2 Mapper 接口
定義根據(jù)用戶名查詢用戶的方法:
@Mapper
public interface UsersMapper {
Users selectByLoginAct(@Param("loginAct") String loginAct);
}5.3 Mapper XML
<mapper namespace="cn.edu.nnu.opengms.ss02.mapper.UsersMapper">
<select id="selectByLoginAct" resultMap="BaseResultMap">
SELECT * FROM users WHERE username = #{loginAct}
</select>
</mapper>5.4 UserService 接口
定義服務(wù)接口,繼承 UserDetailsService:
public interface UserService extends UserDetailsService {
// 只需實現(xiàn) loadUserByUsername 方法
}5.5 UserServiceImpl 實現(xiàn)
核心實現(xiàn)類,從數(shù)據(jù)庫加載用戶:
@Service
public class UserServiceImpl implements UserService {
@Resource
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Users users = usersMapper.selectByLoginAct(username);
if (users == null) {
throw new UsernameNotFoundException("用戶不存在");
}
// 將數(shù)據(jù)庫用戶轉(zhuǎn)換為 Spring Security 的 UserDetails 對象
UserDetails userDetails = User.builder()
.username(users.getUsername())
.password(users.getPassword())
.authorities(AuthorityUtils.NO_AUTHORITIES)
.build();
return userDetails;
}
}這里的 User 是 Spring Security 提供的構(gòu)建器類,用于簡化 UserDetails 對象的創(chuàng)建。
5.6 PasswordEncoder 配置
在 Spring 容器中注冊密碼編碼器:
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// BCrypt:單向哈希算法,自帶隨機(jī)鹽,安全性高
return new BCryptPasswordEncoder();
}
}六、數(shù)據(jù)庫準(zhǔn)備
創(chuàng)建數(shù)據(jù)庫和用戶表:
CREATE TABLE `users` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL UNIQUE,
`password` VARCHAR(100) NOT NULL,
`email` VARCHAR(100),
`phone` VARCHAR(20),
`enabled` TINYINT(1) DEFAULT 1,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;注意:數(shù)據(jù)庫中的密碼必須是 BCrypt 加密后的密文,可以使用 BCrypt 工具類生成。
6.1 使用 IDEA 插件 Free MyBatis Tool 生成 Mapper 與 XML
在這個模塊里,你也可以使用 IntelliJ IDEA 插件 Free MyBatis Tool 來快速生成基礎(chǔ)代碼,減少手寫重復(fù)勞動。
常見流程如下:
- 在 IDEA 安裝插件:
Free MyBatis Tool - 配置數(shù)據(jù)源并連接目標(biāo)數(shù)據(jù)庫(如
spring_security_demo) - 選中目標(biāo)表(如
users)后執(zhí)行代碼生成 - 生成實體類、Mapper 接口、Mapper XML(以及可選 Service/Controller 模板)
生成后建議重點(diǎn)檢查以下幾項(這一步很重要):
namespace是否與 Mapper 接口全限定名一致- XML 中
id是否與接口方法名一致(如selectByLoginAct) mapper-locations是否與 XML 實際路徑一致- 參數(shù)名與 SQL 占位符是否一致(必要時配合
@Param)
示例(生成后可按項目需要補(bǔ)充自定義查詢):
@Mapper
public interface UsersMapper {
Users selectByLoginAct(@Param("loginAct") String loginAct);
}<mapper namespace="cn.edu.nnu.opengms.ss02.mapper.UsersMapper">
<select id="selectByLoginAct" resultMap="BaseResultMap">
SELECT * FROM users WHERE username = #{loginAct}
</select>
</mapper>提示:代碼生成能提高效率,但不要完全依賴默認(rèn)模板。安全相關(guān)字段(如 password、enabled)和登錄查詢 SQL 仍建議人工復(fù)核。
七、核心概念總結(jié)
| 概念 | 說明 |
|---|---|
| UserDetailsService | 自定義認(rèn)證服務(wù)接口,loadUserByUsername() 方法由框架自動調(diào)用 |
| UserDetails | 用戶信息封裝對象,包含用戶名、密碼、權(quán)限 |
| UserDetailsBuilder | 構(gòu)建器,簡化 UserDetails 對象創(chuàng)建 |
| PasswordEncoder | 密碼編碼器,Spring Security 7.x 必須配置 |
| 認(rèn)證流程 | 框架自動調(diào)用數(shù)據(jù)庫查詢,驗證密碼 |
八、總結(jié)
本篇文章介紹了以下核心概念:
- UserDetailsService:自定義認(rèn)證服務(wù)接口
- UserDetails:用戶信息封裝對象
- PasswordEncoder:密碼編碼器,必須配置
- 認(rèn)證流程:框架自動調(diào)用數(shù)據(jù)庫查詢,驗證密碼
- BCrypt:推薦使用的密碼編碼算法
以上就是SpringSecurity整合MyBatis實現(xiàn)數(shù)據(jù)庫認(rèn)證的詳細(xì)步驟的詳細(xì)內(nèi)容,更多關(guān)于SpringSecurity MyBatis數(shù)據(jù)庫認(rèn)證的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用JSON.toJSONString格式化成json字符串時保留null屬性
這篇文章主要介紹了使用JSON.toJSONString格式化成json字符串時保留null屬性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring事務(wù)注解如何確保你的應(yīng)用數(shù)據(jù)的一致性
Spring事務(wù)注解用于確保電商平臺下單過程中數(shù)據(jù)一致性,通過ACID原則、傳播行為、隔離級別和回滾配置管理數(shù)據(jù)庫操作,合理設(shè)置屬性及拆分事務(wù)方法可提升系統(tǒng)穩(wěn)定性與可靠性,本文介紹Spring事務(wù)注解如何確保你的應(yīng)用數(shù)據(jù)的一致性,感興趣的朋友一起看看吧2025-07-07
Java 指定微信好友自動發(fā)送消息的實現(xiàn)示例
這篇文章主要介紹了Java 指定微信好友自動發(fā)送消息的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
java開發(fā)使用StringUtils.split避坑詳解
這篇文章主要為大家介紹了java開發(fā)使用StringUtils.split避坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例
本文主要介紹了Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05
使用Spring的AbstractRoutingDataSource實現(xiàn)多數(shù)據(jù)源切換示例
這篇文章主要介紹了使用Spring的AbstractRoutingDataSource實現(xiàn)多數(shù)據(jù)源切換示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-02-02

