SpringSecurity系列之基于数据库认证

本文中所使用的技术栈如下:
SpringBoot 2.6.2
MyBatis Plus 3.5.0
SpringSecurity 5.6.1

一、创建数据库表

如下图所示,创建一个简单的用户数据表,实际开发中应当使用密文存储密码,而不是如下当中的明文存储。

springbottsqlserver2014数据库 DBUtils springsecurity数据库_spring

二、创建SpringBoot应用

1.配置application.properties文件

主要是配置数据库连接信息

# 指定端口号
server:
  port: 8888

# 配置数据库连接信息
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/security-demo
    username: root
    password: kenewstar

2.配置pom.xml文件

主要引入SpringSecurity依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gitee.security</groupId>
    <artifactId>springboot-security</artifactId>
    <version>0.0.1</version>
    <name>springboot-security</name>
    <description>Security project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <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>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.创建SpringBoot启动类

/**
 * @author kenewstar
 * @date 2022/1/20
 */
@RestController
@MapperScan("com.gitee.security.mapper")
@SpringBootApplication
public class SpringbootSecurityApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringbootSecurityApplication.class, args);
   }

   @GetMapping("/test")
   public String test() {
      return "SpringSecurity";
   }
}

启动类上加一个@RestController注解,并添加一个/test接口用于访问我们的web程序。

4.创建一个用户实体类

/**
 * 用户实体类
 * @author kenewstar
 * @date 2022/1/20
 */
@Data
@TableName("sys_user")
public class SysUser {
   private Integer id;
   private String username;
   private String password;
}

@Data注解属于lombok中用于简化实体类的getter/setter方法。
@TableName注解用于标注实体类映射一个数据库表,value值为数据表名称。

5.创建UserMapper

/**
 * @author kenewstar
 * @date 2022/1/20
 */
public interface UserMapper extends BaseMapper<SysUser> {

}

创建UserMapper.java文件,继承MyBatisPlus中的CRUD通用接口BaseMapepr用于访问数据库。

三、配置SpringSecurity

1.重写UserDetailsService接口

package com.gitee.security.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gitee.security.mapper.UserMapper;
import com.gitee.security.pojo.SysUser;
import java.util.Objects;
import javax.annotation.Resource;
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;

/**
 * @author kenewstar
 * @date 2022/1/20
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

   @Resource
   private UserMapper userMapper;

   @Override
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      // 通过username查询数据库中的用户信息
      QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
      queryWrapper.eq("username", username);
      // 获取数据库查询的用户信息
      SysUser sysUser = this.userMapper.selectOne(queryWrapper);
      // 校验用户对象是否存在
      if (Objects.isNull(sysUser)) {
         throw new  UsernameNotFoundException("用户不存在");
      }
      User.UserBuilder builder = User.builder();
      UserDetails admin = builder.username(sysUser.getUsername())
            // 实际上是从数据库中直接取出加密后的密码,而不是在此处加密
            .password(new BCryptPasswordEncoder().encode(sysUser.getPassword()))
            .roles("admin")
            .build();
      // 返回用户对象
      return admin;
   }
}

重写UserDetailsService接口用于获取数据库用户信息并校验返回用户对象。
引入UserMapper对象,并重写loadUserByUsername()方法,见名知意,通过用户名加载用户对象,返回UserDetails对象该对象包含了返回的用户信息对象。传入参数username为前端表单输入的用户名。

2.配置SpringSecurity配置类

package com.gitee.security.config;

import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
 * Spring Security 配置类
 * @author kenewstar
 * @date 2022/1/20
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Resource
   private UserDetailsService userDetailsService;

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
   }

   @Bean
   public PasswordEncoder passwordEncoder() {
      return new BCryptPasswordEncoder();
   }
}

创建SpringSecurity配置类,重写configure(AuthenticationManagerBuilder auth)方法,将我们重写的UserDetailService对象添加进来,并且还需要配置PasswordEncoder对象(必须配置)密码加密对象,用于加密数据库密码。

四、测试验证

启动SpringBoot应用并访问/test接口

访问地址:http://127.0.0.1:8888/test

springbottsqlserver2014数据库 DBUtils springsecurity数据库_spring_02


由于我们没有登录系统,所以会直接跳转至登录页面,我们输入admin/123456用户名和密码。

springbottsqlserver2014数据库 DBUtils springsecurity数据库_spring boot_03


登录成功如下:

springbottsqlserver2014数据库 DBUtils springsecurity数据库_User_04


登录失败如下:

springbottsqlserver2014数据库 DBUtils springsecurity数据库_SpringSecurity_05