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 查到用户必须返回对象,没查到抛异常
相关推荐
RyFit24 分钟前
SpringAI 常见问题及解决方案大全
java·ai
石山代码37 分钟前
C++ 内存分区 堆区
java·开发语言·c++
绝知此事1 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
无风听海1 小时前
C# 隐式转换深度解析
java·开发语言·c#
lzhdim1 小时前
SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题
数据库·sql
瀚高PG实验室2 小时前
瀚高企业版V9.1.1在pg_restore还原备份文件时提示extract函数语法问题
数据库·瀚高数据库
一只大袋鼠2 小时前
Git 进阶(二):分支管理、暂存栈、远程仓库与多人协作
java·开发语言·git
TDengine (老段)2 小时前
TDengine Tag 设计哲学与 Schema 变更机制
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
德思特2 小时前
从 Dify 配置页理解 RAG 的重要参数
java·人工智能·llm·dify·rag
YOU OU3 小时前
Spring IoC&DI
java·数据库·spring