SpringSecurity系列之基于数据库认证
本文中所使用的技术栈如下:
SpringBoot 2.6.2
MyBatis Plus 3.5.0
SpringSecurity 5.6.1
一、创建数据库表
如下图所示,创建一个简单的用户数据表,实际开发中应当使用密文存储密码,而不是如下当中的明文存储。
二、创建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
由于我们没有登录系统,所以会直接跳转至登录页面,我们输入admin/123456用户名和密码。
登录成功如下:
登录失败如下: