3.SpringSecurity基于数据库的认证与授权

这篇具有很好参考价值的文章主要介绍了3.SpringSecurity基于数据库的认证与授权。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringSecurity基于数据库的认证与授权

承接:2.SpringSecurity - 处理器简单说明-CSDN博客

我们之前学习的用户的信息都是配置在代码中,如下段代码所示

/**
 * 定义一个Bean,用户详情服务接口
 * <p>
 * 系统中默认是有这个UserDetailsService的,也就是默认的用户名(user)和默认密码(控制台生成的)
 * 如果在yaml文件中配置了用户名和密码,那在系统中的就是yaml文件中的信息
 * <p>
 * 我们自定义了之后,就会把系统中的UserDetailsService覆盖掉
 */
@Configuration
public class MySecurityUserConfig {
    /**
     * 根据用户名把用户的详情从数据库中获取出来,封装成用户细节信息UserDetails(包括用户名、密码、用户所拥有的权限)
     * <p>
     * UserDetails存储的是用户的用户名、密码、去权限信息
     */
    @Bean
    public UserDetailsService userDetailsService() {
//      用户细节信息,创建两个用户
//      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainer
        UserDetails user1 = User.builder()
                .username("zhangjingqi-1")
                .password(passwordEncoder().encode("123456"))
//               配置用户角色
                .roles("student") //角色到系统中会变成权限的,比如这里会变成ROLE_student,ROLE_manager
                .build();

        UserDetails user2 = User.builder()
                .username("zhangjingqi-2")
                .password(passwordEncoder().encode("123456"))
//              配置权限
                .authorities("teacher:query")
                .build();

        UserDetails user3 = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("123456"))
//              配置权限
                .authorities("teacher:query","teacher:add","teacher:update","teacher:delete")
                .build();

//      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsService
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(user1);
        userDetailsManager.createUser(user2);
        userDetailsManager.createUser(user3);
        return userDetailsManager;
    }

    /**
     * 配置密码加密器
     * NoOpPasswordEncoder.getInstance() 此实例表示不加密
     * BCryptPasswordEncoder() 会加密
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

但是我们并不希望上面这样写,我们希望把用户的信息存入到数据库

一、自定义用户信息UserDetails

用户实体类需要实现UserDetails接口,并实现该接口中的7个方法, UserDetails 接口的7个方法如下图

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

1.1 新建用户信息类UserDetails

//只有当"accountNonExpired"、“accountNonLocked”、“credentialsNonExpired”、"enabled"都为true时,账户才能使用
//之前我们创建的时候,直接User.builder()创建,之后InMemoryUserDetailsManager对象createUser
public class SecurityUser implements UserDetails {

    /**
     * @return 权限信息
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    /**
     * @return 用户密码,一定是加密后的密码
     */
    @Override
    public String getPassword() {
        //明文为123456
        return "$2a$10$KyXAnVcsrLaHMWpd3e2xhe6JmzBi.3AgMhteFq8t8kjxmwL8olEDq";
    }

    /**
     * @return 用户名
     */
    @Override
    public String getUsername() {
        return "thomas";
    }

    /**
     * @return 账户是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * @return 账户是否被锁住
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * @return 凭据是否过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * @return 账户是否可用
     */
    @Override
    public boolean isEnabled() {
        return true;
    }
}

1.2 UserDetailsService

/**
 * 当我们定义了此类后,系统默认的UserDetailsService不会起作用,下面UserServiceImpl会起作用
 */
@Service
public class UserServiceImpl implements UserDetailsService {

    /**
     * 根据用户名获取用户详情UserDetails
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SecurityUser securityUser= new SecurityUser();//我们自己定义的
        if(username==null || !username.equals(securityUser.getUsername())){
//          SpringSecurity框架中自带的异常
            throw new UsernameNotFoundException("该用户不存在或用户名不正确");
        }
//      执行到这里,说明username是没有问题的
//      用户密码对不对,框架会帮我们进行判断
        return securityUser;
    }

}

二、基于数据库的认证

我们观察到在1.1UserDetails中,我们把用户名和密码是写死的,但是这种情况下是不合理的,包括权限在内,我们都需要从数据库中取出来

将信息从数据库取出来后,可以将信息封装成一个UserDetails类

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

2.1 连接数据库

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

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.15</version>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>
spring:
  #数据源
  datasource:
    #德鲁伊连接池
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springsecurity?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: root
      
 mybatis:
  #SQL映射文件的位置
  mapper-locations: classpath:mapper/**/*.xml
  # 指定实体类起别名,(实体类所在的包的包路径,那么包中的所有实体类别名就默认是类名首字母小写)
  type-aliases-package: com.zhangjingqi.entity
  configuration:
    #开启驼峰命名法
    map-underscore-to-camel-case: true
    #日志功能
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl     

2.2 获取用户信息

判断用户是否正确,我们可以从sys_user中取出用户相关信息,将用户的相关信息取出来后封装成一个UserDetails类

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

2.2.1 获取用户实体类

获取用户信息的实体类,这里不建议SysUser实体类实现UserDetails接口,因为会显得很乱

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SysUser implements Serializable {

    private static final long serialVersionUID = -5352627792860514242L;
    
    private Integer userId;

    private String username;

    private String password;

    private String sex;

    private String address;

    private Integer enabled;

    private Integer accountNoExpired;

    private Integer credentialsNoExpired;

    private Integer accountNoLocked;

}

2.2.2 Mapper

封装dao层,也就是Mapper层,从数据库中获取用户的信息

@Mapper
public interface SysUserDao {

    /**
     * 根据用户名访问用户信息
     * @param userName 用户名
     * @return 用户信息
     */
    SysUser getByUserName(@Param("userName") String userName);


}
<mapper namespace="com.zhangjingqi.dto.SysUserDao">

    <select id="getByUserName" resultType="com.zhangjingqi.entity.SysUser">
         select user_id,username,password,sex,address,enabled,account_no_expired,credentials_no_expired,account_no_locked
        from sys_user 
        where username = #{userName};
    </select>
    
</mapper>

2.2.3 Service

@Slf4j
@Service
public class SysUserServiceImpl implements SysUserService {
    
    @Autowired
    private SysUserDao sysUserDao;

    @Override
    public SysUser getByUserName(String userName) {
        return sysUserDao.getByUserName(userName);
    }
}

2.3 认证

2.3.1 实现UserDetails接口

我们之前是写死的用户信息,但是现在是从数据库中进行获取的

@Data
public class SecurityUser implements UserDetails {

    private static final long serialVersionUID = -1314948905954698478L;

    private final SysUser sysUser ;


    public SecurityUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }


    /**
     * @return 权限信息
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    /**
     * @return 用户密码,一定是加密后的密码
     */
    @Override
    public String getPassword() {
        return sysUser.getPassword();
    }

    /**
     * @return 用户名
     */
    @Override
    public String getUsername() {
        return sysUser.getUsername();
    }

    /**
     * @return 账户是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return sysUser.getAccountNoExpired() != 0;
    }

    /**
     * @return 账户是否被锁住
     */
    @Override
    public boolean isAccountNonLocked() {
        return sysUser.getAccountNoLocked() !=0;
    }

    /**
     * @return 凭据是否过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return sysUser.getCredentialsNoExpired() !=0 ;
    }

    /**
     * @return 账户是否可用
     */
    @Override
    public boolean isEnabled() {
        return sysUser.getEnabled() !=0 ;
    }
}

这个地方我们之前是这么写的

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

2.3.2 实现UserDetailsService接口

@Slf4j
@Service
public class SecurityUserDetailsService implements UserDetailsService {

    @Autowired
    private SysUserService sysUserService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

//      1.从数据库获取用户的详情信息
        SysUser sysUser = sysUserService.getByUserName(username);

        if (null == sysUser){
//          这个异常信息是SpringSecurity中封装的
            throw new UsernameNotFoundException("用户没有找到");
        }

//      2.封装成UserDetails类,SecurityUser类实现了UserDetails接口
        SecurityUser securityUser = new SecurityUser(sysUser);

        return securityUser;
    }
}

我们之前是这么写的

这篇文章会有介绍:1.SpringSecurity -快速入门、加密、基础授权-CSDN博客

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

2.3.3 安全配置类

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 重写 configure(HttpSecurity http)方法
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()//授权http请求
                .anyRequest()//任何请求
                .authenticated();//需要验证

        http.formLogin().permitAll(); //SpringSecurity的表单认证
    }


    /**
     * @return 密码加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

2.3.4 测试程序

2.3.4.1 控制器
@RestController
@RequestMapping("/student")
public class StudentController {

    @GetMapping("/query")
    private String query(){
        return "query student";
    }

    @GetMapping("/add")
    private String add(){
        return "add student";
    }

    @GetMapping("/delete")
    private String delete(){
        return "delete student";
    }

    @GetMapping("/update")
    private String update(){
        return "export student";
    }
}
@RestController
@RequestMapping("/teacher")
public class TeacherController {

    @GetMapping("/query")
    @PreAuthorize("hasAuthority('teacher:query')")//预授权
    public String queryInfo() {
        return "teacher query";
    }

}
3.3.4.1 访问

用下面这个人的信息进行登录

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

访问一下localhost:8080/student/query,发现可以访问

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

再访问一下localhost:8080/teacher/query,发现是不能访问的,原因是thomas用户没有/teacher/query路径的权限

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

三、基于数据库的授权

3.1 数据库表

首先我们很明确的就是用户和角色的关系是多对多的

用户表

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

角色表

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

用户与角色关联表

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

权限表

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

权限与角色关联表

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

3.2 获取权限

3.2.1 权限类 SysMenu

@Data
public class SysMenu implements Serializable {
    
    private static final long serialVersionUID = 597868207552115176L;
    
    private Integer id;
    private Integer pid;
    private Integer type;
    private String name;
    private String code;
}

3.2.2 SysMenuDao

@Mapper
public interface SysMenuDao {
   List<String> queryPermissionByUserId(@Param("userId") Integer userId);
}

这个地方涉及到三张表,角色用户关联表sys_role_user、角色权限关联表sys_role_menu、权限表sys_menu

我们要实现通过用户获取对应的权限

<mapper namespace="com.zhangjingqi.dto.SysMenuDao">


    <select id="queryPermissionByUserId" resultType="java.lang.String">
        SELECT distinct sm.code
        FROM sys_role_user sru
                 inner join sys_role_menu srm
                            on sru.rid = srm.rid
                 inner join sys_menu sm on srm.mid = sm.id
        where sru.uid = #{userId}
          and sm.delete_flag = 0

    </select>
</mapper>

3.2.3 SysMenuServiceImpl

@Service
public class SysMenuServiceImpl implements SysMenuService {
    @Autowired
    private SysMenuDao sysMenuDao;

    @Override
    public List<String> queryPermissionByUserId(Integer userId) {
        return sysMenuDao.queryPermissionByUserId(userId);
    }
}

3.2.4 修改 UserDetailsService

@Slf4j
@Service
public class SecurityUserDetailsService implements UserDetailsService {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysMenuService sysMenuService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

//      1.从数据库获取用户的详情信息
        SysUser sysUser = sysUserService.getByUserName(username);

        if (null == sysUser){
//          这个异常信息是SpringSecurity中封装的
            throw new UsernameNotFoundException("用户没有找到");
        }

//      2.获取该用户的权限
        List<String> permissionList = sysMenuService.queryPermissionByUserId(sysUser.getUserId());

//        List<SimpleGrantedAuthority> simpleGrantedAuthorities = permissionList.stream().map(permission -> new SimpleGrantedAuthority(permission) ).collect(Collectors.toList());
//      将集合的泛型转换成SimpleGrantedAuthority (GrantedAuthority类的子类即可)
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = permissionList.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());


//      2.封装成UserDetails类,SecurityUser类实现了UserDetails接口
        SecurityUser securityUser = new SecurityUser(sysUser);
        securityUser.setSimpleGrantedAuthorities(simpleGrantedAuthorities);

        return securityUser;
    }
}

3.2.5 修改 UserDetails

@Data
public class SecurityUser implements UserDetails {

    private static final long serialVersionUID = -1314948905954698478L;

    private final SysUser sysUser ;

//  用户权限
    private List<SimpleGrantedAuthority> simpleGrantedAuthorities;

    public SecurityUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }


    /**
     *  这个集合中对象的类型必须是GrantedAuthority类或其子类
     * @return 权限信息
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return simpleGrantedAuthorities;
    }

    /**
     * @return 用户密码,一定是加密后的密码
     */
    @Override
    public String getPassword() {
        return sysUser.getPassword();
    }

    /**
     * @return 用户名
     */
    @Override
    public String getUsername() {
        return sysUser.getUsername();
    }

    /**
     * @return 账户是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return sysUser.getAccountNoExpired() != 0;
    }

    /**
     * @return 账户是否被锁住
     */
    @Override
    public boolean isAccountNonLocked() {
        return sysUser.getAccountNoLocked() !=0;
    }

    /**
     * @return 凭据是否过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return sysUser.getCredentialsNoExpired() !=0 ;
    }

    /**
     * @return 账户是否可用
     */
    @Override
    public boolean isEnabled() {
        return sysUser.getEnabled() !=0 ;
    }
}

3.3 测试

使用Obama登录

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

查看obama权限

3.SpringSecurity基于数据库的认证与授权,# SpringSecurity,spring,spring boot,后端,mysql

四、总结

认证与授权,需要我们实现UserDetails用户详情类和UserDetailsService类文章来源地址https://www.toymoban.com/news/detail-722027.html

到了这里,关于3.SpringSecurity基于数据库的认证与授权的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot集成SpringSecurity从0到1搭建权限管理详细过程(认证+授权)

    最近工作需要给一个老系统搭建一套权限管理,选用的安全框架是SpringSecurity,基本上是结合业务从0到1搭建了一套权限管理,然后想着可以将一些核心逻辑抽取出来写一个权限通用Demo,特此记录下。 Spring Security是 Spring家族中的一个安全管理框架。相比与另外一个安全框架

    2024年02月04日
    浏览(40)
  • 系列八、Spring Security中基于Mybatis Plus的用户认证 & 授权

           【上篇】文章介绍了基于Jdbc的用户认证 授权,虽然实现了在数据库中认证和授权的逻辑,但是底层都是Spring Security底层帮我们定义好的,扩展性不强,企业开发中,常用的持久化方案是MyBatis Plus,那么Spring Security中如何定义基于MyBatis Plus的方式进行认证授权呢?请看

    2024年01月18日
    浏览(47)
  • Gateway+Springsecurity+OAuth2.0+JWT 实现分布式统一认证授权!

    目录 1. OAuth2.0授权服务 2. 资源服务 3. Gateway网关 4. 测试   在SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心-CSDN博客 ​​​​​​ 基础上整合网关和JWT实现分布式统一认证授权。   大致流程如下: 1、客户端发出请求给网关获取令牌 2、网关收到请求,直接转发给授权服务

    2024年01月24日
    浏览(51)
  • 【数据库二】数据库用户管理与授权

    CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同,在存储或检索过程中不进行大小写转换。 下表显示了将各种字符串值保存到CHAR(4)和VARCHAR(4)列后的结果,说明了CHAR和VARCHAR之间的差别: 字节大小 char无论是否有值,都

    2024年02月09日
    浏览(45)
  • 基于Spring boot的图书商城管理系统-源码、数据库、LW

    框架:Springboot 数据库:MySQL 下载链接: https://download.csdn.net/download/yw1990128/87851197 B站运行链接: 基于Springboot的图书商城管理系统_哔哩哔哩_bilibili 引言 项目开发背景 Internet最早在美国出现,如今,世界各国纷纷加入到这个行列,便Internet成 为全球化的网际网络。随着用户的

    2024年02月07日
    浏览(52)
  • 基于Spring注解 + MyBatis + Servlet 实现数据库交换的小小Demo

    配置数据库连接信息 db.properties 配置web.xml 配置logback.xml配置文件 配置applicationContext.xml 里面的bean 配置myBatis核心配置文件mybatis-config.xml 创建实体类对象User 创建LoginServlet响应前端的数据 创建UserService 接口 创建UserMapper接口 创建UserServiceImpl 接口实现类 按照这样的方式进行拼接

    2024年02月02日
    浏览(80)
  • 基于Spring Boot和Vue3的博客平台数据库设计实践

    在构建一个博客平台时,数据库设计是关键的一步。一个合理的数据库设计可以提高数据的一致性、完整性和可用性,从而提高整个平台的稳定性和性能。本篇博客将介绍博客平台的数据库设计,包括实体关系图、表结构设计以及表之间的关系。 1. 实体关系图 实体关系图(

    2023年04月14日
    浏览(53)
  • pg数据库授权

    创建用户角色 此处说明,在pg库里面用户和角色的概念其实无区别 授权命令 授权参数说明 权限撤销 如果用户需要创建表的权限对该角色进行全部授权之后,发现建表的时候报错说什么当前用户是一个readonly的会话可以进行下面操作进行修改 参考连接:https://blog.csdn.net/eagl

    2024年02月11日
    浏览(48)
  • 【数据库】 mysql用户授权详解

    目录 MySQL用户授权 一,密码策略 1,查看临时密码 2,查看数据库当前密码策略: 二, 用户授权和撤销授权 1、创建用户 2,删除用户 3,授权和回收权限 mysql刚安装时,临时密码会存储在 /var/log/mysqld.log 1,查看临时密码 方法一:直接给出密码   方法二:查到的语句的最后为

    2024年02月11日
    浏览(58)
  • 数据库安全控制——授权及回收权限

    任务描述 本关任务:系统用户 root 授权 user1 用户创建数据库 teachingdb2 及其所有对象的权限 相关知识 为了完成本关任务,你需要掌握 MySQL 的权限管理。 MySql系统库中的权限表 MySql 系统库中的权限表: user:最重要的权限表,存储允许连接到服务器的账号。 db:存储用户对某

    2024年02月05日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包