4、security之自定义数据源

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 4、security之自定义数据源

security默认使用的就是内存方式定义数据源

一、基于内存的数据源

1、配置文件方式

默认的用户定义在SecurityProperties里边,是一个静态内部类,如果要定义自己的用户名密码,必然是要去覆盖默认配置,在配置文件中配置

spring.security.user.name=admin
spring.security.user.password=admin
spring.security.user.roles=ADMIN

此时重启项目,就可以使用自己定义的用户名/密码登录了。

2、配置类中重写configure方式

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Bean
    PasswordEncoder passwordEncoder() {
        //暂时先不给密码进行加密,所以返回 NoOpPasswordEncoder 的实例
        return NoOpPasswordEncoder.getInstance();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
//如果需要配置多个用户,用 and 相连
                .withUser("123")
                .password("123").roles("admin");
    }
}

通过重写 WebSecurityConfigurerAdapter 中的 userDetailsService 方法来提供一个 UserDetailService 实例进而配置多个用户:

@Configuration
public class SecurityConfig1 extends WebSecurityConfigurerAdapter {
 
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("admin").password("admin").roles("admin").build());
        manager.createUser(User.withUsername("123").password("123").roles("user").build());
        return manager;
    }
}

4、自定义实现类方式

重写UserDetailsService接口中的loadUserByUsername方法,并在配置类型申明

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;
 
/**
 * 自定义认证服务实现security中的方法
 */
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
 
   //实现security接口类userdetails唯一方法
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
 
        //这个设置一个角色
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
 
        return new User("123",getPass(),authorities);
    }
 
    //对配置的用户密码123进行加密
    public String getPass(){
       return new BCryptPasswordEncoder().encode("123");
    }
}
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
 
import javax.annotation.Resource;
 
@Configuration
public class SecurityConfig1 extends WebSecurityConfigurerAdapter {
 
    //注入自己的实现类
    @Resource
    private MyUserDetailsServiceImpl userDetailsService;
    @Bean
    PasswordEncoder passwordEncoder(){
        return new  BCryptPasswordEncoder();
    }
 
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}

总结:以上四种基于内存的方式认证推荐第二种

二、基于数据库数据源

1、基于默认的数据库模型认证

UserDetailsService 都有哪些实现类

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

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

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

这里面sql语句如下

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 即可。

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

执行完 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("admin")) {
        manager.createUser(User.withUsername("admin").password("123").roles("admin").build());
    }
    if (!manager.userExists("123")) {
        manager.createUser(User.withUsername("123").password("123").roles("user").build());
    }
    return manager;
}
  • 首先构建一个 JdbcUserDetailsManager 实例。
  • 给 JdbcUserDetailsManager 实例添加一个 DataSource 对象。
  • 调用 userExists 方法判断用户是否存在,如果不存在,就创建一个新的用户出来(因为每次项目启动时这段代码都会执行,所以加一个判断,避免重复创建用户)。
  • 用户的创建方法和我们之前 InMemoryUserDetailsManager 中的创建方法基本一致

因为要连接数据库,所以还需导入依赖

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

   <groupId>mysql</groupId>

   <artifactId>mysql-connector-java</artifactId>

</dependency>

配置文件配置

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

2、自定义数据库认证

Spring Security适应系统,而非让系统适应Spring Security,是Spring Security框架开发者和使用者的共识,上面使用了 InMemoryUserDetailsManager 和 JdbcUserDetailsManager 两个UserDetailsService 实现类。生效方式也很简单,只需加入 Spring 的 IoC 容器,就会被 Spring Security自动发现并使用。自定义数据库结构实际上也仅需实现一个自定义的UserDetailsService。

UserDetailsService仅定义了一个loadUserByUsername方法,用于获取一个UserDetails对象。UserDetails对象包含了一系列在验证时会用到的信息,包括用户名、密码、权限以及其他信息

这里结合mybatis认证,需要导入的依赖

<dependency>

   <groupId>org.mybatis.spring.boot</groupId>

   <artifactId>mybatis-spring-boot-starter</artifactId>

   <version>2.0.0</version>

</dependency>

<dependency>

    <groupId>mysql</groupId>

     <artifactId>mysql-connector-java</artifactId>

</dependency>

自定义类

@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
 
    @Resource
    private  UserDao userDao;
   //实现security接口类userdetails唯一方法
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        SysUser user = userDao.getUserByUserName(userName);
        //这里查出结果如:userName = "admin" passWord="$2a$10$FsNmqBMoxqRQAzcjvF8YD.Sqh3SaSkO40FfuC.VraGuKTcTeC3wDm";密码是经过BCryptPasswordEncoder加密的
        if(user==null){
            throw new UsernameNotFoundException("用户不存在");
        }
        //这个设置一个角色
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
 
        return new User(user.getUserName(),user.getPassWord(),authorities);
    }
}

配置类

@Configuration
public class SecurityConfig1 extends WebSecurityConfigurerAdapter {
 
    //注入自己的实现类
    @Resource
    private MyUserDetailsServiceImpl userDetailsService;
 
    @Bean
    PasswordEncoder passwordEncoder(){
        return new  BCryptPasswordEncoder();
    }
 
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
6月前
|
安全 Java 数据库连接
Security自定义全局AuthenticationManager
Security自定义全局AuthenticationManager
198 1
|
4月前
|
安全 Java 数据安全/隐私保护
解析Spring Security中的权限控制策略
解析Spring Security中的权限控制策略
|
6月前
|
安全 Java 数据库
Spring Security自定义登录认证
Spring Security自定义登录认证
159 0
|
6月前
|
安全 架构师 Java
SpringBoot【集成 jasypt】实现配置信息自定义加解密(自定义的属性探测和密码解析器)
SpringBoot【集成 jasypt】实现配置信息自定义加解密(自定义的属性探测和密码解析器)
825 0
|
安全 Java 数据库
Sping Security-3-动态认证用户信息
Sping Security-3-动态认证用户信息
136 1
|
存储 缓存 druid
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
3272 0
基于springboot+jpa 实现多租户动态切换多数据源 - 基于dynamic-datasource实现多租户动态切换数据源
|
安全 前端开发 Java
Spring Security 使用自定义认证页面|学习笔记
快速学习 Spring Security 使用自定义认证页面
Spring Security 使用自定义认证页面|学习笔记
|
安全
Security配置类
学习Security配置Demo1
139 0
|
安全 Java 数据库连接
Spring Security系列教程10--基于自定义数据库模型实现授权
前言 在上一个章节中,一一哥 给大家讲解了如何基于默认的数据库模型来实现认证授权,在这种模型里,用户的信息虽然是保存在数据库中的,但是有很多的限制!因为我们必须按照源码规定的方式去建库建表,存在灵活性不足的问题。而我们真正开发时,用户角色等表肯定要根据自己的项目需求来单独设计,所以我们有必要进行用户及角色表的自定义设计。 那么在本篇文章中,壹哥 就带各位,结合自己的实际项目需求,进行数据库和表的自定义设计,然后在这个自定义的数据库中实现用户信息的认证与授权工作。 一. 核心API源码介绍 1. UserDetailsService源码 在上一章节中,我给大家介绍了一个JdbcUserDeta
810 0