08 - spring security基于jdbc的账号密码
spring security基于jdbc的账号密码
文档
- 00 - spring security框架使用
- 01 - spring security自定义登录页面
- 02 - spring security基于配置文件及内存的账号密码
- 03 - spring security自定义登出页面
- 04 - spring security关闭csrf攻击防御
- 05 - spring security权限控制
- 06 - spring security角色和权限设置
- 07 - spring security基于数据库的账号密码
基于jdbc的账号密码
说明
spring security
自带基于内存的登录认证及基于jdbc的登录认证- 基于jdbc的登录认证会将用户信息及权限信息存储在数据库中,登录认证、添加用户等功能
spring security
已经实现 spring security
提供了sql脚本,能够创建users
表及authorities
表,位置:org\springframework\security\spring-security-core\6.2.0\spring-security-core-6.2.0.jar!\org\springframework\security\core\userdetails\jdbc\users.ddl
,但此脚本不适配mysql,使用时需要调整
配置基于jdbc的账号密码
-
在上篇文章07 - spring security基于数据库的账号密码的基础上进行修改即可
-
在上篇文章中,已经配置了数据源,这里也需要用到数据源
-
在数据库中创建
users
表及authorities
表,spring security提供了sql脚本,但不适配mysql,下面是参考脚本创建
users
表CREATE TABLE `users` (`username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,`PASSWORD` varchar(500) COLLATE utf8mb4_general_ci NOT NULL,`enabled` tinyint(1) NOT NULL,PRIMARY KEY (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
创建
authorities
表CREATE TABLE `authorities` (`username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,`authority` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,UNIQUE KEY `ix_auth_username` (`username`,`authority`),CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-
在上篇文章中,自定义了
UserDetailsManager
的实现类DatabaseUserDetailsManager
,并且接受spring管理,这里需要取消spring管理该类,注释掉DatabaseUserDetailsManager
类上的@Component
注解即可package xin.yangshuai.springsecurity03.config;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.provisioning.UserDetailsManager; import org.springframework.stereotype.Component; import xin.yangshuai.springsecurity03.entity.SpringSecurityUser; import xin.yangshuai.springsecurity03.mapper.SpringSecurityUserMapper;//@Component public class DatabaseUserDetailsManager implements UserDetailsManager { // ... }
-
定义一个
UserDetailsManager
类型的Bean
,实际的实现类是JdbcUserDetailsManager
,既基于jdbc的登录认证。该实现类需要传入数据源,数据源可以直接通过注入的方式获取到@Configuration // @EnableWebSecurity @EnableMethodSecurity //开启基于方法的授权 public class WebSecurityConfig {@Autowiredprivate DataSource dataSource;@Beanpublic UserDetailsManager userDetailsManager() {JdbcUserDetailsManager manager = new JdbcUserDetailsManager();manager.setDataSource(dataSource);if (!manager.userExists("user")) {manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").authorities("USER_LIST").build());}return manager;}// ... }
- 在基于内存的账号密码时,我们定义了一个
UserDetailsService
类型的Bean
,这里定义的是UserDetailsManager
类型的Bean
,实际上UserDetailsManager
是UserDetailsService
的子类,并且有createUser
等方法,后面演示创建用户需要用到,如果仅仅是登录认证,定义UserDetailsService
类型的Bean
是可以的 - 这里默认创建
user
用户,可以用来登录,需要注意的是,创建用户时需要至少分配一个权限,否则无法登录,参考org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl#loadUserByUsername
- 在基于内存的账号密码时,我们定义了一个
-
启动服务,启动成功后,默认创建的用户及对应的权限信息会保存在数据库表中
添加用户
-
创建
UserDetailsController
类,注入UserDetailsManager
类型的对象,UserDetailsManager
类型的对象就是上面定义的基于jdbc认证的Bean
package xin.yangshuai.springsecurity03.controller;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.DelegatingPasswordEncoder; import org.springframework.security.crypto.password.MessageDigestPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.UserDetailsManager; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import xin.yangshuai.common01.entity.BaseResult;import java.util.HashMap; import java.util.Map; import java.util.Random;/*** UserDetailsController** @author shuai* @date 2025/8/28*/ @RestController @RequestMapping("userDetails") public class UserDetailsController {@Autowiredprivate UserDetailsManager userDetailsManager;@GetMapping("add")public BaseResult<Integer> add() {String encodingId = "bcrypt";Map<String, PasswordEncoder> encoders = new HashMap();encoders.put(encodingId, new BCryptPasswordEncoder());encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));// ...encodingId = "MD5";PasswordEncoder encoder = new DelegatingPasswordEncoder(encodingId, encoders);// 这里示例,添加用户int i = new Random().nextInt(100);UserDetails userDetails1 = User.builder().passwordEncoder(encoder::encode).username("test" + i).password("123456").authorities("USER_LIST").build();userDetailsManager.createUser(userDetails1);BaseResult<Integer> result = new BaseResult<>();result.setCode("200");result.setData(1);return result;} }
-
注入的
UserDetailsManager
类型的对象就是上面定义的基于jdbc认证的Bean
,createUser
方式是spring security
已经实现的逻辑,执行后,即可添加用户及权限到数据库中 -
spring security
进行账号认证的时候,loadUserByUsername
方法返回的UserDetails
对象的密码是需要传入加密的,在基于jdbc的账号认证中,loadUserByUsername
方法返回的UserDetails
对象的密码是保持数据库原始密码不变的,所以在创建用户的时候直接对密码进行加密