本章将介绍如何将 mysql 数据库中的用户信息接入 spring security,告别配置文件中的内存用户。
一、问题切入
第一章中我们通过配置文件指定用户:
spring:
security:
user:
name: flittly
password: 123456这种方式存在明显缺陷:
- 用户信息写在代码中,无法动态管理
- 密码以明文形式存储,安全性低
- 生产环境不应使用配置文件明文密码
- 无法扩展更多用户,无法支持注册/注销等功能
我们需要一个可扩展的方案,将数据库中的用户信息加载到 spring security 中。
二、解决方案:引入 mybatis
在 pom.xml 中添加 mybatis starter 和 mysql 驱动:
<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>三、配置数据源连接
在 application.yml 中配置数据库连接:
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四、原理阐释:认证流程
4.1 核心接口
spring security 的认证体系围绕以下核心接口展开:
| 接口 | 作用 |
|---|---|
| userdetailsservice | 根据用户名加载用户信息 |
| userdetails | 用户信息封装对象 |
| passwordencoder | 密码验证器 |
| authentication | 认证令牌 |
4.2 认证流程详解
整个认证流程涉及多个组件的协作:
用户提交登录表单(用户名 + 密码)
↓
usernamepasswordauthenticationfilter 拦截请求
↓ 提取用户名
daoauthenticationprovider.getuserdetails(username)
↓ 调用
userdetailsservice.loaduserbyusername(username)
↓ 调用 mybatis mapper
从数据库查询用户信息
↓ 返回
构建 userdetails 对象(含密码、权限信息)
↓
passwordencoder.matches() 验证密码
↓ 匹配成功
authentication 认证成功,创建认证令牌
↓
securitycontextholder.getcontext().setauthentication()
↓
重定向到成功页面userdetailsservice 是 spring security 认证体系的核心接口,负责根据用户名加载用户信息。
4.3 密码编码器
spring security 7.x 要求必须配置密码编码器,支持多种编码方式:
- bcrypt:推荐,单向哈希算法,内置随机盐
- argon2:现代密码哈希算法
- pbkdf2:基于密钥推导
- scrypt:计算密集型算法
bcrypt 是目前最常用的选择,它具有以下特点:
- 单向哈希:无法从哈希值反向推导原始密码
- 内置盐:每次加密生成不同的哈希值,即使相同密码也不一样
- 强度可调:通过 work factor 调整计算时间
五、代码实现
5.1 users 实体类
对应数据库中的 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 接口
定义根据用户名查询用户的方法:
@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 接口
定义服务接口,继承 userdetailsservice:
public interface userservice extends userdetailsservice {
// 只需实现 loaduserbyusername 方法
}5.5 userserviceimpl 实现
核心实现类,从数据库加载用户:
@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("用户不存在");
}
// 将数据库用户转换为 spring security 的 userdetails 对象
userdetails userdetails = user.builder()
.username(users.getusername())
.password(users.getpassword())
.authorities(authorityutils.no_authorities)
.build();
return userdetails;
}
}这里的 user 是 spring security 提供的构建器类,用于简化 userdetails 对象的创建。
5.6 passwordencoder 配置
在 spring 容器中注册密码编码器:
@configuration
public class securityconfig {
@bean
public passwordencoder passwordencoder() {
// bcrypt:单向哈希算法,自带随机盐,安全性高
return new bcryptpasswordencoder();
}
}六、数据库准备
创建数据库和用户表:
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;注意:数据库中的密码必须是 bcrypt 加密后的密文,可以使用 bcrypt 工具类生成。
6.1 使用 idea 插件 free mybatis tool 生成 mapper 与 xml
在这个模块里,你也可以使用 intellij idea 插件 free mybatis tool 来快速生成基础代码,减少手写重复劳动。
常见流程如下:
- 在 idea 安装插件:
free mybatis tool - 配置数据源并连接目标数据库(如
spring_security_demo) - 选中目标表(如
users)后执行代码生成 - 生成实体类、mapper 接口、mapper xml(以及可选 service/controller 模板)
生成后建议重点检查以下几项(这一步很重要):
namespace是否与 mapper 接口全限定名一致- xml 中
id是否与接口方法名一致(如selectbyloginact) mapper-locations是否与 xml 实际路径一致- 参数名与 sql 占位符是否一致(必要时配合
@param)
示例(生成后可按项目需要补充自定义查询):
@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>提示:代码生成能提高效率,但不要完全依赖默认模板。安全相关字段(如 password、enabled)和登录查询 sql 仍建议人工复核。
七、核心概念总结
| 概念 | 说明 |
|---|---|
| userdetailsservice | 自定义认证服务接口,loaduserbyusername() 方法由框架自动调用 |
| userdetails | 用户信息封装对象,包含用户名、密码、权限 |
| userdetailsbuilder | 构建器,简化 userdetails 对象创建 |
| passwordencoder | 密码编码器,spring security 7.x 必须配置 |
| 认证流程 | 框架自动调用数据库查询,验证密码 |
八、总结
本篇文章介绍了以下核心概念:
- userdetailsservice:自定义认证服务接口
- userdetails:用户信息封装对象
- passwordencoder:密码编码器,必须配置
- 认证流程:框架自动调用数据库查询,验证密码
- bcrypt:推荐使用的密码编码算法
以上就是springsecurity整合mybatis实现数据库认证的详细步骤的详细内容,更多关于springsecurity mybatis数据库认证的资料请关注代码网其它相关文章!
发表评论