一篇文章带你搞定 Spring Security 将用户数据存储到数据库

一、UserDetailService

Spring Security 支持多种不同的数据源,这些不同的数据源最终都将被封装成 UserDetailsService 的实例,在微人事(https://github.com/lenve/vhr)项目中,我们是自己来创建一个类实现 UserDetailsService 接口,除了自己封装,我们也可以使用系统默认提供的 UserDetailsService 实例,例如上篇文章和大家介绍的 InMemoryUserDetailsManager

我们来看下 UserDetailsService 都有哪些实现类:

Inserte la descripción de la imagen aquí
可以看到,在几个能直接使用的实现类中,除了 InMemoryUserDetailsManager 之外,还有一个 JdbcUserDetailsManager,使用 JdbcUserDetailsManager 可以让我们通过 JDBC 的方式将数据库和 Spring Security 连接起来。

这里需要加入jdbc 和mysql 依赖:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
</dependency>     

二、JdbcUserDetailsManager

JdbcUserDetailsManager 自己提供了一个数据库模型,这个数据库模型保存在如下位置:

org/springframework/security/core/userdetails/jdbc/users.ddl

这里存储的脚本内容如下:

create table users(username varchar_ignorecase(50) not null primary key,password varchar_ignorecase(500) not null,enabled boolean not null);
create table authorities (username varchar_ignorecase(50) not null,authority varchar_ignorecase(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

可以看到,脚本中有一种数据类型 varchar_ignorecase,这个其实是针对 HSQLDB 数据库创建的,而我们使用的 MySQL 并不支持这种数据类型,所以这里需要大家手动调整一下数据类型,将 varchar_ignorecase 改为 varchar 即可。

create table users(username varchar(50) not null primary key,password varchar(500) not null,enabled boolean not null);
create table authorities (username varchar(50) not null,authority varchar(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

修改完成后,创建数据库,执行完成后的脚本。

Inserte la descripción de la imagen aquí
执行完 SQL 脚本后,我们可以看到一共创建了两张表:users 和 authorities。

users 表中保存用户的基本信息,包括用户名、用户密码以及账户是否可用。
authorities 中保存了用户的角色。
authorities 和 users 通过 username 关联起来。

配置完成后,接下来,我们将上篇文章中通过 InMemoryUserDetailsManager 提供的用户数据用 JdbcUserDetailsManager 代替掉,如下:

	@Autowired
    DataSource dataSource;

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
    
    
        JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
        manager.setDataSource(dataSource);
        if (!manager.userExists("yolo")) {
    
    
            manager.createUser(User.withUsername("yolo").password("123").roles("admin").build());
        }
        if (!manager.userExists("nlcs")) {
    
    
            manager.createUser(User.withUsername("nlcs").password("123").roles("user").build());
        }
        return manager;
    }

这段配置的含义如下:

(1)首先构建一个 JdbcUserDetailsManager 实例。
(2)给 JdbcUserDetailsManager 实例添加一个 DataSource 对象。
(3)调用 userExists 方法判断用户是否存在,如果不存在,就创建一个新的用户出来(因为每次项目启动时这段代码都会执行,所以加一个判断,避免重复创建用户)。
(4)用户的创建方法和我们之前 InMemoryUserDetailsManager 中的创建方法基本一致。

这里的 createUser 或者 userExists 方法其实都是调用写好的 SQL 去判断的,我们从它的源码里就能看出来(部分):

public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsManager,
  GroupManager {
    
    
 public static final String DEF_USER_EXISTS_SQL = "select username from users where username = ?";

 private String userExistsSql = DEF_USER_EXISTS_SQL;

 public boolean userExists(String username) {
    
    
  List<String> users = getJdbcTemplate().queryForList(userExistsSql,
    new String[] {
    
     username }, String.class);

  if (users.size() > 1) {
    
    
   throw new IncorrectResultSizeDataAccessException(
     "More than one user found with name '" + username + "'", 1);
  }

  return users.size() == 1;
 }
}

从这段源码中就可以看出来,userExists 方法的执行逻辑其实就是调用 JdbcTemplate 来执行预定义好的 SQL 脚本,进而判断出用户是否存在,其他的判断方法都是类似,我就不再赘述。

三、数据库支持

通过前面的代码,大家看到这里需要数据库支持,所以我们在项目中添加如下两个依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

然后再在 application.properties 中配置一下数据库连接:

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

因为这里选择的是 Mysql 8 所以配置信息里需要加入:serverTimezone=Asia/Shanghai

配置完成后,就可以启动项目。

项目启动成功后,我们就可以看到数据库中自动添加了两个用户进来,并且用户都配置了角色。如下图:

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

四、测试登录

接下来我们就可以进行测试了。

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Durante el proceso de prueba, si el usuario de la base de datos enabledestableció las propiedades para false, deshabilita la cuenta, los fallos de reingreso utilizarán la cuenta para iniciar sesión.

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/nanhuaibeian/article/details/108602260
Recomendado
Clasificación