【SpringSecurity】六、基于数据库的认证与授权

news2024/11/25 21:25:47

文章目录

  • 1、数据库表设计
  • 2、测试代码准备
  • 3、新建安全用户类
  • 4、实现UserDetailsService接口
  • 5、授权

1、数据库表设计

接下来基于数据库里的用户信息进行登录认证,以RBAC设计表,分别为:

  • 用户表sys_user :除了基本信息外,注意一些开关字段

在这里插入图片描述

  • 角色表sys_role:包括角色id,角色名称(存英文),以及备注(中文释义)

在这里插入图片描述

  • 用户角色中间表sys_role_user :存两个多对多实体各自的主键

在这里插入图片描述

  • 菜单权限表sys_menu:存权限,一个权限对应一个功能

在这里插入图片描述

  • 角色权限关系表sys_role_menu:存角色和权限这两个多对多实体的主键

在这里插入图片描述

2、测试代码准备

整合mybatis做数据库的增删改查:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

配置数据源和mybatis相关信息:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/testDBy?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root123
mybatis:
  type-aliases-package: com.llg.entity
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   # 打印SQL
  mapper-locations: classpath:mapper/*.xml  # xml文件位置

sys_user表的PO类:

@Data
public class SysUser implements Serializable {
    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;

}

mapper层新建一个查询接口:

public interface SysUserDao {
    /**
     * 根据用户名获取用户信息
     * @param username
     * @return
     */
    SysUser getByUserName(@Param("username") String username);
}

mapper目录下新建映射文件SysUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.llg.dao.SysUserDao">
    <select id="getByUserName" resultType="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>

启动类加@MapperScan注解,指明下mapper层接口的位置:

@SpringBootApplication
@MapperScan("com.llg.dao")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

3、新建安全用户类

新建安全用户类,继承UserDetails,并和库里的SysUser类做转换。(注意这种思路两个类之间做转换,一个类做为属性定义在另一个类中)

public class SecurityUser implements UserDetails {

    private  final SysUser sysUser;

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

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;   //注意权限数据暂时还未做处理
    }

    @Override
    public String getPassword() {
        String userPassword=this.sysUser.getPassword();
		//注意清除密码
		this.sysUser.setPassword(null);
		return userPassword;

    }

    @Override
    public String getUsername() {
        return sysUser.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return sysUser.getAccountNoExpired().equals(1);
    }

    @Override
    public boolean isAccountNonLocked() {
        return sysUser.getAccountNoLocked().equals(1);
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return sysUser.getCredentialsNoExpired().equals(1);
    }

    @Override
    public boolean isEnabled() {
        return sysUser.getEnabled().equals(1);
    }
}

到此,实现了将基于数据库自定义的SysUser对象和返给框架的UserDetails对象做了关联。

4、实现UserDetailsService接口

@Service
public class UserServiceImpl implements UserDetailsService {
    @Resource
    private SysUserDao sysUserDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = sysUserDao.getByUserName(username);
        if(null==sysUser){
            throw new UsernameNotFoundException("账号不存在");
        }
        return new SecurityUser(sysUser);
    }
}

如果能在数据库查到这个用户,就将他包装成UserDetails的格式返给框架。接下来补个安全配置类:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
        http.formLogin();
    }
}

此时用户是可以正常登录的。但没有权限信息,写个接口查看权限信息:

在这里插入图片描述
返回数据没权限信息:
在这里插入图片描述

5、授权

再来处理权限部分,要实现根据用户名查询权限,RBAC下需要联结三张表来查,新建Mapper接口:

List<String> queryPermissionByUserId(@Param("userId") Integer userId);

映射文件SysMenuMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.llg.dao.SysUserDao">
    <select id="queryPermissionByUserId" resultType="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>

修改上面定义的SecurityUser类,加入权限。新增属性并加Set方法

private List<SimpleGrantedAuthority> simpleGrantedAuthorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return simpleGrantedAuthorities;
}

整体:

在这里插入图片描述

修改UserServiceImpl实现类,加入权限信息:

@Service
@Slf4j
public class UserServiceImpl implements UserDetailsService {
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private SysMenuDao sysMenuDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = sysUserDao.getByUserName(username);
        if(null==sysUser){
            throw new UsernameNotFoundException("账号不存在");
        }
        //查到权限
        List<String> strList=sysMenuDao.queryPermissionByUserId(sysUser.getUserId());
		//使用stream流来转换
        List<SimpleGrantedAuthority> grantedAuthorities=strList.stream().map(SimpleGrantedAuthority::new).collect(toList());
        SecurityUser securityUser = new SecurityUser(sysUser);
        securityUser.setSimpleGrantedAuthorities(grantedAuthorities);
        return securityUser;
    }
}

以上使用Stream流做了个转换,把一个个String对象转为了SimpleGrantedAuthority对象,再赋值给对象的权限属性,也可for循环:

 //查到权限
 List<String> strList=sysMenuDao.queryPermissionByUserId(sysUser.getUserId());
 List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
 for(String s:strList){
	SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(s);
	grantedAuthorities.add(simpleGrantedAuthority);
 }
 securityUser.setSimpleGrantedAuthorities(grantedAuthorities);
 .....

再查看权限:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/969868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch(b站小土堆学习笔记P1-P15)

P3. Python学习中的两大法宝函数&#xff08;当然也可以用在PyTorch&#xff09; import torch#查看pytorch有哪些指令 print(dir(torch)) print(dir(torch.cuda)) #查看每条指令怎么用 help(torch.cuda.is_available) P4. PyCharm及Jupyter使用及对比 P5 dataset和dataloade…

肖sir__设计测试用例方法之场景法04_(黑盒测试)

设计测试用例方法之场景法 1、场景法主要是针对测试场景类型的&#xff0c;顾也称场景流程分析法。 2、流程分析是将软件系统的某个流程看成路径&#xff0c;用路径分析的方法来设计测试用例。根据流程的顺序依次进行组合&#xff0c;使得流程的各个分支能走到。 举例说明&…

Pinely Round 2 (Div. 1 + Div. 2) F. Divide, XOR, and Conquer(区间dp)

题目 给定长为n(n<1e4)的数组&#xff0c;第i个数为ai(0<ai<2的60次方) 初始时&#xff0c;区间为[1,n]&#xff0c;也即l1&#xff0c;rn&#xff0c; 你可以在[l,r)中指定一个k&#xff0c;将区间分成左半边[l,k]、右半边[k1,r] 1. 如果左半边异或和与异或和的异…

肖sir__设计测试用例方法之判定表06_(黑盒测试)

设计测试用例方法之判定表 1、判定表&#xff1a;是一种表达逻辑判断的工具。 2、判定表&#xff1a;包含四部分 1&#xff09;条件桩&#xff08;condition stub&#xff09;:列出问题的 所有条件&#xff08;通常条件次序无关紧要&#xff09;。 2&#xff09;条件项&#x…

面试官:介绍一下CSS定位?absolute和relative分别依据什么定位?

能说服一个人的&#xff0c;从来不是道理&#xff0c;而是南墙。 一、position属性介绍 取值名称效果static静态定位(默认值)元素按照标准流布局 (不脱标) , top、bottom、left 、right等属性不起作用relative相对定位元素按照标准流布局 (不脱标) &#xff0c;可以通过top、b…

Medium:做AB test需要多少时间?

文章链接&#xff1a;https://medium.com/alfredcamera/%E5%81%9A-ab-test-%E9%9C%80%E8%A6%81%E5%A4%9A%E5%B0%91%E6%99%82%E9%96%93-c401fbe00eb0 其中&#xff0c;最关键的是确定&#xff1a;总共需要多少样本数量。由以下2个指标决定&#xff1a; 由工具得到&#xff1a; 特…

监听器Listener -,钝化,活化,利用监听器实现简易版 统计网站在线用户功能

监听绑定到HttpSession域中某个对象状态 1.HttpSessionBindingListener 实体类 package com.etime.enetity;import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener;//此处需要实现HttpSessionBindingListener接口&…

使用MDK5的一些偏僻使用方法和谋个功能的作用

程序下载后无法运行 需要勾选如下库&#xff0c;是优化后的库&#xff1b; MicroLib和标准C库之间的主要区别是: 1、MicroLib是专为深度嵌入式应用程序而设计的。 2、MicroLib经过优化&#xff0c;比使用ARM标准库使用更少的代码和数据内存。 3、MicroLib被设计成在没有操作…

科技成果鉴定之鉴定测试报告

鉴定测试 由于软件类科技成果的复杂、内部结构难以鉴别等特点&#xff0c;我们提供了软件类科技成果鉴定测试服务。软件类科技成果鉴定测试是依据其科研项目计划任务书或技术合同书&#xff0c;参照相应的国家标准对要申请鉴定的软件类科技成果进行的一种符合性测试&#xff0…

【100天精通Python】Day51:Python 数据分析_数据分析入门基础与Anaconda 环境搭建

目录 1 科学计算和数据分析概述 2. 数据收集和准备 2.1 数据收集 2.1.1 文件导入&#xff1a; 2.1.2 数据库连接&#xff1a; 2.1.3 API请求&#xff1a; 2.1.4 网络爬虫&#xff1a; 2.2 数据清洗 2.2.1 处理缺失值&#xff1a; 2.2.2 去除重复值&#xff1a; 2.2…

数学建模--Python绘图

目录 1.绘制散点图 1.1.绘制过程解释 1.2.绘制图像代码 1.3.绘制图像展示 2.绘制折线统计图 2.1.绘制过程解释 2.2.绘制图像代码 2.3.绘制图像展示 3.绘制柱形图 3.1.绘制图像解释 3.2.绘制图像代码 3.3.绘制图像展示 4.多种图形的综合绘制 4.1.绘制图像解释 4.2.绘制图像…

二级web操作题(1-6)

第二套 1.对数组排序 <html> <title>对数组排序</title> <body> <script> //生成一个m、n之间的整数 function rand(m,n){ /* **********Found********** */ var iMath.random(); /* **********Found********** */ return Math.round((n-m…

内存管理之:内存空间分布和栈攻击(黑客常用攻击手段)

目录 C语言内存管理及栈攻击 内存管理 Linux虚拟内存空间分布&#xff08;重要&#xff09; 栈溢出&#xff08;栈攻击&#xff09; 堆栈的特点 栈攻击 栈攻击的实现 原理 编译器选项 实现案例 linux修改栈空间大小方式 内存泄漏 如何避免野指针&#xff1f; 如何…

C++智能指针之weak_ptr(保姆级教学)

目录 C智能指针之weak_ptr 概述 作用 本文涉及的所有程序 使用说明 weak_ptr的常规操作 lock(); use_count(); expired(); reset(); shared_ptr & weak_ptr 尺寸 智能指针结构框架 常见使用问题 shared_ptr多次引用同一数据&#xff0c;会导致两次释放同一内…

Medium:How to check the correctness of the AB test?

有以下两种错误&#xff1a; 通常&#xff0c;type 1 error is more important&#xff01;因此我们type 2 error就是在“委曲求全”&#xff1a; The probability of Type II error can be adjusted to the desired value by changing the size of the groups or by reducing…

【LeetCode每日一题合集】2023.8.14-2023.8.20(⭐切披萨3n块披萨)

文章目录 617. 合并二叉树833. 字符串中的查找与替换&#xff08;模拟&#xff09;2682. 找出转圈游戏输家&#xff08;模拟&#xff09;1444. 切披萨的方案数&#xff08;⭐⭐⭐⭐⭐&#xff09;解法——从递归到递推到优化&#xff08;二维前缀和记忆化搜索&#xff09; 1388…

【LeetCode每日一题合集】2023.8.7-2023.8.13(动态规划分治)

文章目录 344. 反转字符串1749. 任意子数组和的绝对值的最大值&#xff08;最大子数组和&#xff09;1281. 整数的各位积和之差1289. 下降路径最小和 II解法1——动态规划 O ( n 3 ) O(n^3) O(n3)解法2——转移过程优化 O ( n 2 ) O(n^2) O(n2) ⭐ 1572. 矩阵对角线元素的和解法…

13.Redis 事务

Redis 事务 redis 事务事务操作multi 开启事务exec 执行事务discard 放弃当前事务watchunwatch redis 事务 Redis 的事务和 MySQL 的事务概念上是类似的。 都是把⼀系列操作绑定成⼀组。 让这⼀组能够批量执⾏。 Redis 的事务和 MySQL 事务的区别: 弱化的原⼦性: 这里指的是 …

Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)

题目 给定一个长度为n(n<1e6)的序列&#xff0c;第i个数ai(1<ai<n)&#xff0c; 操作&#xff1a;你可以将当前i位置的数和a[i]位置的数交换 交换可以操作任意次&#xff0c;求所有本质不同的数组的数量&#xff0c;答案对1e97取模 思路来源 力扣群 潼神 心得 感…

huggingface下载模型文件(基础入门版)

huggingface是一个网站&#xff0c;类似于github&#xff0c;上面拥有众多开源的模型、数据集等资料&#xff0c;人工智能爱好者可以很方便的上面获取需要的数据&#xff0c;也可以上传训练好的模型&#xff0c;制作的数据集等。本文只介绍下载模型的方法&#xff0c;适合新手入…