Spring Security 自定义数据库认证(初尝试)

Spring Security 自定义数据库认证 学习笔记

适配个人实战案例:基于 Spring Boot 3 + Spring Security 6 + MyBatis 实现从MySQL数据库查询用户完成登录认证


一、学习目标

  1. 掌握 Spring Security 替换默认用户,使用数据库用户完成登录认证
  2. 理解 UserDetailsService 核心接口的作用
  3. 学会封装 UserDetails 用户信息对象
  4. 解决集成过程中的常见报错(空指针、类型转换、返回null等)

二、基础环境

1. 核心依赖

xml 复制代码
<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis + MySQL -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

2. 配置文件(application.yml)

配置数据库连接,无需额外配置Security

yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/你的数据库?useSSL=false
    username: root
    password: 你的密码
mybatis:
  mapper-locations: classpath:mapper/*.xml

三、核心代码实现

1. 数据库实体类(User)

com.sy.pojo.User 对应数据库user表

java 复制代码
@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String realName;
    private String phone;
    private Integer status;
    private Date createTime;
}

2. Mapper 层(数据查询)

  1. UserMapper接口
java 复制代码
@Mapper
public interface UserMapper {
    // 根据用户名查询用户(认证核心方法)
    User findByUsername(String username);
}
  1. XML映射文件
xml 复制代码
<select id="findByUsername" resultType="com.sy.pojo.User">
    select * from user where username = #{username}
</select>

3. Service 层(认证核心)

  1. UserService接口(继承Security核心接口)
java 复制代码
public interface UserService extends UserDetailsService {
}
  1. UserServiceImpl实现类
java 复制代码
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * Security 认证核心方法:根据用户名加载用户信息
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1. 从数据库查询用户
        User user = userMapper.findByUsername(username);
        
        // 2. 用户不存在,抛出异常
        if(user == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        
        // 3. 封装为Security要求的UserDetails对象并返回
        return User.withUsername(user.getUsername())
                .password(user.getPassword())
                .authorities(AuthorityUtils.NO_AUTHORITIES)
                .build();
    }
}

4. Security 配置类

配置密码加密器(Security强制要求)

java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    // 密码加密:BCrypt算法
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

四、认证执行流程

  1. 用户提交登录表单 → Security 自动拦截
  2. 调用 loadUserByUsername 方法 → 根据用户名查数据库
  3. 返回 UserDetails 对象 → Security 自动比对密码
  4. 验证通过 → 登录成功;验证失败 → 报错

五、实战常见踩坑总结(重点)

报错信息 错误原因 解决方案
userMapper null 未加@Service / @Mapper 类上添加@Service、Mapper加@Mapper
类型转换异常 自定义User不能直接返回 封装为Security的User对象
UserDetails returned null 方法最后return null 必须return userDetails,禁止返回null
用户名不匹配 登录账号和数据库不一致 使用正确用户名登录

六、核心知识点

  1. UserDetailsService:Security认证的核心接口,自定义认证必须实现它
  2. UserDetails:Security规定的用户信息格式,必须封装后返回
  3. PasswordEncoder:密码加密接口,必须配置,否则无法认证
  4. 禁止返回nullloadUserByUsername 查到用户必须返回对象,没查到抛异常
相关推荐
sinat_255487812 小时前
泛型·学习笔记
java·jvm·数据库·windows·python
wregjru2 小时前
【MySQL】4. 数据约束详解
数据库·sql·oracle
QuZero2 小时前
Java Synchronized principle
java·开发语言
明灯伴古佛2 小时前
面试:Java中乐观锁的实现原理是什么
java·面试·职场和发展
枕书2 小时前
Oracle 19c RAC 双机高可用底座部署手册(PVE 架构版)
数据库·oracle·pve
SimonKing2 小时前
白嫖党狂喜!魔塔社区每天2000次免费大模型调用,真香!
java·后端·程序员
一个有温度的技术博主2 小时前
Redis RDB持久化原理:一次快照背后的“分身术”与“读心术”
数据库·redis·缓存
小孤月2 小时前
关系型数据库:(eg:mysql)支持事务 ACID 特性
数据库