写点什么

SpringBoot3 整合 SpringSecurity6(三) 基于数据库的用户认证

  • 2025-05-06
    福建
  • 本文字数:5283 字

    阅读完需:约 17 分钟

一、认证流程


其实基于数据库的用户认证和基于内存认证大同小异,我们只需要将从内存获取用户信息,换成从数据库获取用户信息即可。


换成代码就是替换掉InMermoryUserDetailManager 实现类,自己去实现UserDetailsService,从数据库查询用户然后返回。



二、SpringBoot3 整合数据库


在进行认证前,我们需要保证SpringBoot能正常整合数据库,查询用户信息。这里我们使用的数据库是MySQL8.0


2.1 创建数据库、表、插入数据


①创建数据库


我们这里创建一个security-demo的数据库


-- 创建数据库CREATE DATABASE `security-demo`;USE `security-demo`;
复制代码


② 创建用户


-- 创建用户表CREATE TABLE `user`(	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,  -- 主键ID	`username` VARCHAR(50) DEFAULT NULL ,  -- 用户名	`password` VARCHAR(500) DEFAULT NULL, -- 密码	`enabled` BOOLEAN NOT NULL -- 是否启用);
复制代码


③ 创建唯一索引


在这里一个用户的用户名username字段肯定是不能重复的,所以要为username创建唯一索引,保证username的唯一


CREATE UNIQUE INDEX `user_username_uindex` ON `user`(`username`); 
复制代码


④ 插入数据


为了方便测试,我们默认插入几个用户。为了安全起见,这里密码采用SpringSecurity默认的bcrypt加密方式。不清楚的小伙可以先不用管,再后面的文章中会详细介绍到密码加密算法


-- 插入用户数据(密码是 "password" )INSERT INTO `user` (`username`, `password`, `enabled`) VALUES('admin', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE),('xiezhr', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE),('xiaofan', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE);
复制代码


2.2 配置 Lombok


为了偷懒,我们还引入了Lombok。 使用Lombok,可以让我们避免写getsettoString等样板式代码。堪称偷懒神器,解放了双手。



① 下面例举了怎么使用Lombok 来偷懒

  • 简化 Getter 和 Setter 方法:在传统的 Java 开发中,你经常需要为每个类的属性手动编写 Getter 和 Setter 方法,但是有了 Lombok,你只需要在属性上加上 @Getter 和 @Setter 注解,Lombok 就会为你自动生成这些方法。

  • 自动生成构造函数:通过 @NoArgsConstructor@RequiredArgsConstructor 或 @AllArgsConstructor 注解,你可以快速生成无参构造函数、带有必需参数的构造函数或者带有全部参数的构造函数。

  • 自动生成 equals 和 hashCode 方法: 通过 @EqualsAndHashCode 注解,Lombok 会根据类的字段自动生成 equals() 和 hashCode() 方法,让你的类更易于比较和使用在集合中。

  • 日志记录更轻松: 使用 @Slf4j 注解,你可以直接在类中使用 log 对象,而无需手动创建日志记录器。

  • 简化异常抛出: 通过 @SneakyThrows 注解,你可以在方法中抛出受检异常,而无需显式地在方法上声明或捕获它们。

  • 数据类简化: 使用 @Data 注解,Lombok 会为你自动生成所有常用方法,如 Getter、Setter、toString() 等,让你的数据类更加简洁。

  • 链式调用: 使用 @Builder 注解,Lombok 可以帮你创建一个更优雅的构建器模式,让你的对象初始化更加流畅。


② IDEA 中安装 Lombok 插件

我们需要再 IDEA 中安装了Lombok插件,才能正式愉快的使用Lombok

根据你的系统依次点击菜单:

  • Windows 系统:File -> Settings... -> Plugins;

  • Mac 系统:IntelliJ IDEA -> Preferences -> Plugins;



点击 Marketplace , 进入插件市场, 输入关键词 lombok, 搜索该插件:



③ 引入依赖

在 pom.xml 文件中添加如下依赖


<dependency>    <groupId>org.projectlombok</groupId>    <artifactId>lombok</artifactId>    <version>1.18.32</version></dependency>
复制代码


2.3 引入 Mybatis Plus


为了方便后续数据库增删改查等操作,我们引入MybatisPuls作为持久层框架。


① Mybatis Plus 简介

有些小伙伴可能还不知道MybatisPuls,这里简单介绍一下,知道的小伙伴直接跳过即可。

用白话文说MybatisPuls是一款操作数据库的框架。它是一个 MyBatis 的增强工具,就像 iPhone手机一般都有个 plus 版本一样,它在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

MyBatis Plus 的愿景是成为 MyBatis 最好的搭档,就像魂斗罗中的 1P2P,基友搭配,效率翻倍。



② 引入依赖

为了整合 mybatis-plus,我们需要在 pom.xml 中引入如下依赖


<dependency>    <groupId>com.baomidou</groupId>    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>    <version>3.5.5</version></dependency>
复制代码


2.4 引入 MySQL 依赖


我们这里数据库使用的是 MySQL,所以还得引入 MySQL 相关依赖


<dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>8.0.33</version></dependency>
复制代码


2.5 完整依赖


最终完整依赖如下


<dependencies>    <!-- web依赖-->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <!--SpringSecurity 依赖-->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-security</artifactId>        <version>3.2.10</version>    </dependency>    <!--lombok依赖-->    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>        <version>1.18.32</version>    </dependency>    <!--SpringBoot3整合mybatis-plus 依赖-->    <dependency>        <groupId>com.baomidou</groupId>        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>        <version>3.5.5</version>    </dependency>    <!--junit依赖-->    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency>    <!--MySQL依赖-->    <dependency>        <groupId>mysql</groupId>        <artifactId>mysql-connector-java</artifactId>        <version>8.0.33</version>    </dependency></dependencies>
复制代码


2.6 配置数据源


application.yml 文件中配置 MySQL 数据源,即 mybatis-plus 日志


# MySQL数据源spring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3308/security-demo    username: root    password: 123456 # MySQL日志mybatis-plus:  configuration:    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
复制代码


2.7 创建实体类


package com.xiezhr.securityindbuser.entity; @TableName("user")@Datapublic class User {    @TableId(value = "id", type = IdType.AUTO)    private Integer id;     @TableField(value = "username")    private String username;     @TableField(value = "password")    private String password;        @TableField(value = "enabled")    private Boolean enabled;}
复制代码


  • @TableName("user") : mybatis-plus注解,用来指定数据库表名。这里实体名称与数据库表名一致,该注解可省略

  • @Data :Lombok注解,用来生成getset方法

  • @TableId(value = "id", type = IdType.AUTO) :mybatis-plus注解,用来指定了字段 id 为表的主键,同时指定主键为自增类型

  • @TableField(value = "username"):mybatis-plus注解,用来指定字段名。这里实体类属性与数据库字段一致,该注解可省略


2.8 Mapper 接口


package com.xiezhr.securityindbuser.mapper; @Mapperpublic interface UserMapper extends BaseMapper<User> {}
复制代码


  • 继承BaseMapper通用类,可以默认帮我们实现基本增删改查


2.9 Service


① 接口

package com.xiezhr.securityindbuser.service; public interface UserService extends IService<User> {}
复制代码


② 实现

package com.xiezhr.securityindbuser.service.impl; @Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
复制代码


2.10 Controller


package com.xiezhr.securityindbuser.controller; @RestController@RequestMapping("/user")public class UserController {     @Autowired    private UserService userService;     @GetMapping("/list")    public List<User> getUserList(){         return userService.list();    }}
复制代码


2.11 测试是否正常获取数据


以上小节中,我们建立了各种类。结构如下



启动服务,浏览器中输入:http://localhost:8080/user/list 看看是否能查出数据库中用户数据?



至此,我们已经成功整合数据库,并且从数据库中查询出了用户信息。


接下来,我们要做的就是把认证流程从内存中获取用户信息替换成我们自己实现从数据库中查询用户信息。


三、基于数据库的用户认证

3.1 认证流程


通过之前基于内存认证分析,我们知道。只要实现UserDetailsService 接口的loadUserByUsername 方法就可以从数据库中获取用户信息。


  • 程序启动时:创建DBUserDetailsManager类,实现接口 UserDetailsService 接口在应用程序中初始化这个类的对象,使 springsecurity 不再从内存中获取用户信息,而是通过我们自己实现类从数据库中查询用户信息。

  • 校验用户时:SpringSecurity 自动使用DBUserDetailsManagerloadUserByUsername方法从数据库中获取 User 对象在UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户名密码和从数据库中获取到的用户信息进行比较,进行用户认证


3.2 创建DBUserDetailsManager


我们在 service 包下创建DBUserDetailsManager 来实现UserDetailsService 接口,替换从内存中获取用户信息。代码如下


package com.xiezhr.securityindbuser.service.impl; public class DBUserDetailsManager implements UserDetailsService {     @Resource    private UserMapper userMapper;    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {         QueryWrapper<User> queryWrapper = new QueryWrapper<User>();        //使用username构造查询条件        QueryWrapper<User> wrapper = queryWrapper.eq("username", username);		//由于用户名不能重复,所以我们使用selectOne查询用户信息即可        User user = userMapper.selectOne(wrapper);        if (user == null) {            //用户不存在,抛出异常            throw new UsernameNotFoundException(username);        } else {            //由于现在还没有权限信息,所以我们构造一个空的权限信息            Collection< GrantedAuthority> authorities = new ArrayList<>();            return new org.springframework.security.core.userdetails.User(                    user.getUsername(),  //                    user.getPassword(),                    user.getEnabled(),                    true,  //用户账户是否没过期                    true, //用户凭证是否没过期                    true, //用户是否未被锁定                    authorities //用户权限信息            );        }    }}
复制代码


3.3 初始化 UserDetailsService


说了一堆理论,那么我们怎么才能让springsecurity不从内存获取用户信息,而是通过上一步创建的DBUserDetailsManager 来查询用户信息。


接下来的就比较关键了,我们只需创建一个WebSecurityConfig,然后创建基于数据库的用户管理器dbUserDetailsManager即可


package com.xiezhr.securityindbuser.config; @Configuration  //标明这个类为配置类,spring应用程序一启动,类中的been 就会被初始化在spring容器中@EnableWebSecurity  //开启spring security 自定义配置public class WebSecurityConfig {     @Bean    public UserDetailsService userDetailsService(){        //创建基于数据库的用户管理器        DBUserDetailsManager dbUserDetailsManager = new DBUserDetailsManager();        return dbUserDetailsManager;    }}
复制代码


当然我们也可以直接在DBUserDetailsManager类上添加@Component注解,也能实现同样的效果


3.4 测试一下


通过上面的步骤,基于数据库的认证基本就完成了。


在整合数据库的时候我们插入了三个用户信息



下面我们来测试下成果,浏览器中输入:http://localhost:8080/user/list



随便输入上面三个用户中一个,admin/password xiezhr/password xiaofan/password 即可正常访问接口



到此,我们成功完成了基于数据库的用户认证功能,是不是很简单呢~


文章转载自:程序员晓凡

原文链接:https://www.cnblogs.com/xiezhr/p/18860890

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot3整合SpringSecurity6(三)基于数据库的用户认证_oracle_电子尖叫食人鱼_InfoQ写作社区