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 查到用户必须返回对象,没查到抛异常
相关推荐
考虑考虑18 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯19 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
青石路1 天前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
像我这样帅的人丶你还1 天前
Java 后端详解(五):Redis 缓存
java·后端·全栈
plainGeekDev1 天前
GreenDAO → Room
android·java·kotlin
jiayou641 天前
KingbaseES 表级与列级加密完全指南
数据库·后端
亦暖筑序1 天前
Java 8老系统AI Workflow实战:把一次性AI对话升级成可恢复工作流
java·后端
敲代码的彭于晏1 天前
Bean 生命周期完全图解:前端同学也能看懂的 Spring 核心机制
java·前端·后端
plainGeekDev1 天前
ButterKnife → ViewBinding
android·java·kotlin
GBASE2 天前
G术时刻 |GBase 8s数据库事务并发控制之封锁技术介绍(下)
数据库