首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【spring-security基础】基于数据库的认证方式

【spring-security基础】基于数据库的认证方式

作者头像
master336
发布2026-06-15 19:21:46
发布2026-06-15 19:21:46
870
举报
通过查询数据库方式进行认证
  • 核心要点
  • 实现思路
    • 1. 数据库设计
    • 2. 框架依赖引入(操作数据库)
    • 3. 创建操作数据库相关内容
    • 4. 【重点】实现UserDetailsService接口
    • 5. 配置数据库连接信息
    • 补充说明
  • 启动项目进行验证
  • 附:

核心要点

通过实现org.springframework.security.core.userdetails.UserDetailsService接口,实现其用户(认证主体)查询方法即可,参见第四步。

实现思路

1. 数据库设计

设计用户数据库表,如:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
CREATE TABLE `user_info` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
  `password` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,
  `remark` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
2. 框架依赖引入(操作数据库)

为框架操作数据库添加依赖,以mybatis-plus为例

代码语言:javascript
复制
 <!-- 引入mybatis-plus -->
 <dependency>
    <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.0</version>
  </dependency>
  <!-- 引入数据库驱动 -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.16</version>
  </dependency>

另外为了简化代码,可以根据需要引入lombok等工具

代码语言:javascript
复制
 <!-- 引入lombok 简化代码 -->
<dependency>
  <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>
3. 创建操作数据库相关内容

这一步需要创建mybatis操作数据库所需的实体和操作接口,示例代码如下:

  • 创建数据库表映射实体
代码语言:javascript
复制
import lombok.Data;

/**
 * 数据库映射实体
 * 映射数据表: user_info
 */
@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private String remark;
}
  • 创建数据操作接口
代码语言:javascript
复制
import cn.com.demo.entity.UserInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

@Repository
public interface UserInfoDao extends BaseMapper<UserInfo> {
}
  • 配置Mapper扫描路径
代码语言:javascript
复制
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


// 配置MybatisMapper扫描路径
@MapperScan("cn.com.demo.dao.**")
@SpringBootApplication(scanBasePackages = "cn.com.demo.**")
public class SecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class,args);
    }
}
4. 【重点】实现UserDetailsService接口

这一步较为关键,为security提供认证主体查询接口,示例代码如下: 代码参考示例如下;

代码语言:javascript
复制
import cn.com.demo.dao.UserInfoDao;
import cn.com.demo.entity.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserDetailService implements UserDetailsService {
    @Autowired
    private UserInfoDao userInfoDao;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Override
    public UserDetails loadUserByUsername(String usename) throws UsernameNotFoundException {
        // 查询数据库
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",usename);
        UserInfo userInfo = userInfoDao.selectOne(queryWrapper);
        if (userInfo ==null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        // 返回认证主体UserDetails
        return new User(userInfo.getUsername(),bCryptPasswordEncoder.encode(userInfo.getPassword()),auths);
    }
}

这里还需要注意下,密码加密的工具类可以自行设置,也可以适用内置的BCryptPasswordEncoder 完成,本demo中将BCryptPasswordEncoder 声明成了spring的一个bean进行管理,当然这里也可以直接使用其new方法完成创建。

5. 配置数据库连接信息

此步骤为提供数据库连接信息,用于完成数据库操作配置;修改配置文件,如:application.yml

代码语言:javascript
复制
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/springsecurity?serverTimezone=Asia/Shanghai
    username: springsecurity
    password: springsecurity@1
    driver-class-name: com.mysql.cj.jdbc.Driver
补充说明

实现UserDetailsService接口的目的是为security提供认证主体相关的信息,这一步也可以通过配置进行覆盖,示例代码如下:

代码语言:javascript
复制
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
       // 声明 认证主体服务对象及加密方式
        authenticationManagerBuilder.userDetailsService(userDetailService).passwordEncoder(bCryptPasswordEncoder);
    }
  }

启动项目进行验证

编写测试接口,访问即可完成测试(记得数据库中添加用户及密码信息)

附:

  1. 临时配置用户名密码可参考【spring-security基础】基于配置的用户名密码设置及适用场景说明
  2. 密码建议加密后存储到数据库中,实际代码中使用BCryptPasswordEncoder进行密码加密的做法并不是要求密码一定要明文存储。当数据库中存储的密码是加密的,这个时候可以通过实现自己的PasswordEncoder完成认证接口明文到密文的转换,以比对加密后的密码是否一致(即重写其密码匹配检查方法)。

重写密码加密demo示例

代码语言:javascript
复制
import cn.com.demo.util.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyPasswordEncoder implements PasswordEncoder {
    /**
     * 加密密码
     * @param rawPassword 原始密码
     * @return
     */
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5.encrypt(rawPassword.toString());
    }

    /**
     * 【重点】密码比对
     * @param rawPassword 原始密码(页面提交过来的)
     * @param encodedPassword 已存储的密码(数据库等)
     * @return
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equalsIgnoreCase(MD5.encrypt(rawPassword.toString()));
    }
}

配置自定义密码加密

代码语言:javascript
复制
import cn.com.demo.service.UserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailService userDetailService;
    @Autowired
    private MyPasswordEncoder myPasswordEncoder;
    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        //设置自定义的密码加密方式
        authenticationManagerBuilder.userDetailsService(userDetailService).passwordEncoder(myPasswordEncoder);
    }
}

使用自定义的PasswordEncoder 时要注意在四步的时候设置认证主体的密码应该对应匹配,即如果数据查询出来的已经是加密之后的密码,第四步就不应该再进行加密。

  1. 以上源码参见: 明文存储demo源码 基于MD5加密的demo源码
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-01-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 通过查询数据库方式进行认证
  • 核心要点
  • 实现思路
    • 1. 数据库设计
    • 2. 框架依赖引入(操作数据库)
    • 3. 创建操作数据库相关内容
    • 4. 【重点】实现UserDetailsService接口
    • 5. 配置数据库连接信息
    • 补充说明
  • 启动项目进行验证
  • 附:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档