SpringBoot整合JWT+Spring Security+Redis实现登录拦截(二)权限认证

上篇博文中我们已经实现了登录拦截,接下来我们继续补充代码,实现权限的认证

一、RBAC权限模型

        什么事RBAC权限模型?

        RBAC权限模型(Role-Based Access Control)即:基于角色的权限访问控制。在RBAC中,权限与角色关联,用户通过赋予角色而获得相应角色的权限。故我们需要如下几张表:

        用户表:系统接口及访问的操作者

        权限表:能够访问某接口或者做某操作的授权资格

        角色表:具有一类相同操作权限的用户的总称

        用户角色表:用户角色相关联的表

        角色权限表:角色与权限相关联的表

二、创建对应的数据库表

        可根据项目需要增加或删减、修改对应的表字段

        sys_user

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'ID',`nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',`gender` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',`phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号码',`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',`role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色ID',`is_admin` bit(1) NULL DEFAULT b'0' COMMENT '是否为admin账号',`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',`enabled` bit(1) NULL DEFAULT NULL COMMENT '是否启用',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统用户' ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

 sys_role

DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'ID',`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',`level` int(0) NULL DEFAULT NULL COMMENT '角色级别',`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

sys_menu

DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'ID',`pid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '上级菜单ID',`sub_count` int(0) NULL DEFAULT 0 COMMENT '子菜单数目',`type` int(0) NULL DEFAULT NULL COMMENT '菜单类型',`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单标题',`menu_sort` int(0) NULL DEFAULT NULL COMMENT '排序',`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图标',`path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '链接地址',`cache` bit(1) NULL DEFAULT b'0' COMMENT '缓存',`hidden` bit(1) NULL DEFAULT b'0' COMMENT '隐藏',`permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 118 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统菜单' ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

sys_user_role

DROP TABLE IF EXISTS `sys_users_roles`;
CREATE TABLE `sys_users_roles`  (`user_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户ID',`role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色ID',PRIMARY KEY (`user_id`, `role_id`) USING BTREE,INDEX `user_id`(`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色关联' ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

sys_role_menu

DROP TABLE IF EXISTS `sys_roles_menus`;
CREATE TABLE `sys_roles_menus`  (`role_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色ID',`menu_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单ID',PRIMARY KEY (`role_id`, `menu_id`) USING BTREE,INDEX `FKcngg2qadojhi3a651a5adkvbq`(`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色菜单关联' ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

三、生成5张基础表对应的Java代码

        可自行书写或使用mybatis工具进行生成,也可参考之前的博文

mybatis-plus自动生成代码(整理版)_mybatisplus代码自动生成-CSDN博客文章浏览阅读111次。整理版,添加了注释模版,常用基础方法。也可直接替换成公共的或自己代码中自定义的。仅提供基础方法,可根据具体需求自行改造。仅提供基础方法,可根据具体需求自行改造。仅提供基础方法,可根据具体需求自行改造。_mybatisplus代码自动生成https://blog.csdn.net/shaogaiyue9745602/article/details/134525030?spm=1001.2014.3001.5502

四、鉴权实现

  1.创建PermissionMapper.xml

           变现sql根据用户ID查询角色对应的权限

<?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.hng.mapper.PermissionMapper"><select id="selectPermsByUserId" resultType="java.lang.String">SELECTDISTINCT m.permissionFROMsys_users_roles urLEFT JOIN sys_role r ON ur.role_id = r.idLEFT JOIN sys_roles_menus	rm ON ur.role_id = rm.role_idLEFT JOIN sys_menu m ON m.id = rm.menu_idWHEREuser_id = #{userId}</select>
</mapper>

2.创建PermissionMapper

package com.hng.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hng.entity.SysMenu;import java.util.List;/*** <p>* 系统菜单 Mapper 接口* </p>** @author 郝南过* @since 2023-12-19*/
public interface PermissionMapper extends BaseMapper<SysMenu> {List<String> selectPermsByUserId(String userId);
}

3.改造SecurityUser

    (1)改造构造函数增加权限集合

    private List<String> permissions;public SecurityUser(SysUser user, List<String> permissions) {this.user = user;this.permissions = permissions;}

    (2)改造getAuthorities

    @Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {//将permissions中的String类型的权限信息封装成SimpleGrantedAuthority对象if(authorities!=null){return authorities;}authorities = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());return authorities;}

 4.改造UserDetailsServiceImpl

        修改loadUserByUsername方法,使用Permission增加权限查询

package com.hng.config.security;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hng.config.exception.customize.EntityNotFoundException;
import com.hng.modules.system.entity.SysUser;
import com.hng.modules.system.mapper.PermissionMapper;
import com.hng.modules.system.mapper.SysMenuMapper;
import com.hng.modules.system.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;/*** @Author: 郝南过* @Description: 将Security拦截的用户名密码改为数据库中已有的用户名密码,Security自己校验密码,默认使用PasswordEncoder,格式为{id}password(id代表加密方式),* 一般不采用此方式,SpringSecurity提供了BcryptPasswordEncoder,只需将此注入到spring容器中。SpringSecurity就会使用它进行替换校验* @Date: 2023/12/11 11:29* @Version: 1.0*/
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {@Resourceprivate SysUserService sysUserService;@Resourceprivate PermissionMapper permissionMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户信息LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper();queryWrapper.eq(SysUser::getUserName,username);SysUser user = sysUserService.getOne(queryWrapper);if(Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}//查询授权信息List<String> permissions = permissionMapper.selectPermsByUserId(user.getId());//判断用户是否是管理员,如果是管理员添加admin权限if(user.getIsAdmin()){permissions.add("admin");}return new SecurityUser(user,permissions);}
}

5.自定义权限检测

      可直接使用已有的权限检测@PreAuthorize(“hasAuthority('自定义字符串')”),hasAuthority是系统提供的,可直接使用,也可以自定义。以下为自定义,为方便直接判断admin用户,并给admin用户授予所有权限。

PermissionConfig
package com.hng.config.security;import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;/*** 自定义权限检测*/
@Component(value = "ex")
public class PermissionConfig {public Boolean check(String... permissions) {// 获取当前用户的所有权限Authentication authentication = SecurityContextHolder.getContext().getAuthentication();SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();List<String> exPermissions = securityUser.getPermissions();// 判断当前用户的所有权限是否包含接口上定义的权限return exPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(exPermissions::contains);}
}

6.在SecurityConfig中添加注解

@EnableGlobalMethodSecurity(prePostEnabled = true)//开启权限权限认证

7.在Cotroller中添加对应的权限字符

        如果未自定义权限检测使用注解@PreAuthorize(“hasAuthority('自定义字符串')”),本篇博文中的例子已经自定义为@PreAuthorize("@ex.check('自定义字符串')")

  SysUserController 示例

package com.hng.controller;import lombok.RequiredArgsConstructor;
import io.swagger.annotations.ApiOperation;
import com.hng.config.response.ResponseResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import io.swagger.annotations.ApiParam;import com.hng.entity.SysUser;
import com.hng.service.SysUserService;/*** <p>* 系统用户 前端控制器* </p>*/
@Slf4j
@Api(value = "SysUser", tags = "SysUser")
@RestController
@RequiredArgsConstructor //Lombok的一个注解,简化@Autowired
@RequestMapping("/sys-user")
public class SysUserController {private final SysUserService sysUserService;@PostMapping("/getList")@ApiOperation("sysUser列表查询")@PreAuthorize("@ex.check('SysUser:list')")public ResponseResult queryAllSysUser(@Validated @RequestBody SysUser sysUser){List<SysUser> list = sysUserService.queryAll(sysUser);return ResponseResult.success(list);}@PostMapping("/add")@ApiOperation("新增SysUser")@PreAuthorize("@ex.check('SysUser:add')")public ResponseResult addSysUser(@Validated @RequestBody SysUser sysUser){sysUserService.addSysUser(sysUser);return ResponseResult.success();}/*** 根据ID查询数据* @param id ID*/@GetMapping("getById/{id}")@ApiOperation("sysUser根据Id查询")@ResponseBody@PreAuthorize("@ex.check('SysUser:getById')")public ResponseResult getById(@PathVariable Integer id) {return ResponseResult.success(sysUserService.getSysUserById(id));}/*** 更新数据* @param sysUser 实体对象*/@PutMapping("update")@ApiOperation("sysUser更新")@ResponseBody@PreAuthorize("@ex.check('SysUser:edit')")public ResponseResult update(@Validated @RequestBody SysUser sysUser) {sysUserService.updateSysUser(sysUser);return ResponseResult.success();}/*** 删除数据* @param id ID*/@DeleteMapping("delete/{id}")@ApiOperation("sysUser根据Id删除")@ResponseBody@PreAuthorize("@ex.check('SysUser:del')")public ResponseResult delete(@PathVariable Integer id) {sysUserService.deleteSysUser(id);return ResponseResult.success();}}

五.数据库中添加数据

        根据自己定义的权限字符串与用户进行数据添加

六.测试

        使用pomstman进行测试,注此时可以测试上篇博文中的权限认证异常处理器

 【demo示例代码】

https://download.csdn.net/download/shaogaiyue9745602/88661442icon-default.png?t=N7T8https://download.csdn.net/download/shaogaiyue9745602/88661442

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

若依SQL Server开发使用教程

1. sys_menu表中的将菜单ID修改为自动ID,解决不能增加菜单的问题&#xff0c;操作流程如下&#xff1a; 解决方案如下 菜单栏->工具->选项 点击设计器&#xff0c;去掉阻止保存要求更新创建表的更改选项&#xff0c;点确认既可以保存了 2 自动生成代码找不表的解决方案…

Nature Perspective | LLMs 作为角色扮演引擎

文章目录 一、前言二、主要内容三、总结 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 随着对话智能体的表现越来越像人&#xff0c;我们必须开发出有效的方法&#xff0c;在不陷入拟人化陷阱的情况下&#xff0c;用高层次的术语描述它们的…

Dubbo入门直接上手,结合微服务详解

Dubbo 高性能、轻量级的 Java RPC 框架 RPC&#xff1a; Remote Procedure Call 远程过程调用&#xff0c;简单来说就是它允许一个计算机程序通过网络请求调用另一个计算机上的程序&#xff0c;就像本地调用一样。有非常多的协议和技术来都实现了RPC的过程&#xff0c;比如&a…

【大数据存储与处理】开卷考试总复习笔记

文章目录 实验部分一、 HBase 的基本操作1. HBase Shell入门2. HBase创建数据库表3. HBase数据操作4. HBase删除数据库表5. HBase Python基本编程 before二、 HBase 过滤器操作1.创建表和插入数据2.行键过滤器3.列族与列过滤器4.值过滤器5.其他过滤器6.python hbase 过滤器编程…

Kubernetes(K8S)快速入门

概述 在本门课程中&#xff0c;我们将会学习K8S一些非常重要和核心概念&#xff0c;已经操作这些核心概念对应组件的相关命令和方式。比如Deploy部署&#xff0c;Pod容器&#xff0c;调度器&#xff0c;Service服务&#xff0c;Node集群节点&#xff0c;Helm包管理器等等。 在…

程序员收入与支出 对比分析网红的收入来源

无法收回&#xff0c;就不要花出去。钱只花在增值的事上。 保证一年基本生存的钱不能花。 大额支出要全家协商一致才能花。&#xff08;别把全家坑了&#xff09; 作为程序员&#xff0c;您的收入和支出可以从以下几个方面来考虑&#xff1a; 收入 基本薪资&#xff1a;这是…

C# 使用Pipelines处理Socket数据包

写在前面 在上一篇中对Pipelines进行简单的了解&#xff0c;同时也留下了未解的问题&#xff0c;如何将Pipelines类库运用到Socket通讯过程中来解决粘包和分包。链接地址如下&#xff1a; 初识System.IO.Pipelines https://rjcql.blog.csdn.net/article/details/135211047 这…

【Web API系列】使用getDisplayMedia来实现录屏功能

文章目录 前言一、认识getD该处使用的url网络请求的数据。二、使用步骤1.使用方法一实现录屏2.使用方法二实现录屏3. 运行效果 延伸 前言 Web API经过长期的发展&#xff0c;尤其是最近&#xff0c;发展相当迅猛&#xff0c;现在已经支持很多功能了&#xff0c;一些原生就支持…

IRIS、Cache系统类汉化

文章目录 系统类汉化简介标签说明汉化系统包说明效果展示类分类%Library包下的类重点类非重点类弃用类数据类型类工具类 使用说明 系统类汉化 简介 帮助小伙伴更加容易理解后台系统程序方法使用&#xff0c;降低代码的难度。符合本土化中文环境的开发和维护&#xff0c;有助于…

月入7K, 95后护士转行网优,疫情之后,我选择辞掉“铁饭碗”

成为一个三甲医院的护士是什么体验&#xff1f; 如果你一毕业后就进入一家三甲医院&#xff0c;你可能会享受到稳定的就业环境、近在咫尺的机会与资源。 看似稳定与不错的薪资待遇&#xff0c;成为疫情之后普通打工人挤破脑袋也要进入的存在。似乎也能理解各地医院招聘时动辄80…

每日一题-----逆序字符串

大家好我是Beilef&#xff0c;在一个美好的下午我意外接触到编程并且产生了兴趣&#xff0c;哈哈我要努力成为一个跨界者&#xff0c;让我们一起加油吧O(∩_∩)O 文章目录 目录 文章目录 前言 大家好请上车 一、逆序字符串 题⽬描述&#xff1a; 输⼊⼀个字符串&#xff0c;写…

LabVIEW进行激光斑点图像处理与分析

LabVIEW进行激光斑点图像处理与分析 近年来&#xff0c;激光技术的应用日益繁荣。激光光斑的质量评估和分析技术决定了应用效果&#xff0c;对机器视觉、武器装备、光学测量和医疗设备产生深远影响。就具体用途和技术而言&#xff0c;激光光斑的采集和处理至关重要。即插即用的…

第十五节TypeScript 接口

1、简介 接口是一系列抽象方法的声明&#xff0c;是一些方法特征的集合&#xff0c;这些方法都应该是抽象的&#xff0c;需要有由具体的类去实现&#xff0c;然后第三方就可以通过这组抽象方法调用&#xff0c;让具体的类执行具体的方法。 2、接口的定义 interface interface_…

ElasticSearch 架构设计

介绍 ElasticSearchMySQLIndexTableDocumentRowFieldColumnMappingSchemaQuery DSLSQLaggregationsgroup by&#xff0c;avg&#xff0c;sumcardinality去重 distinctreindex数据迁移 ElasticSearch 中的一个索引由一个或多个分片组成 每个分片包含多个 segment&#xff08;分…

redis的搭建及应用(三)-Redis主从配置

Redis主从配置 为提升Redis的高可用性&#xff0c;需要搭建多个Redis集群以保证高可用性。常见搭建方式有&#xff1a;主从&#xff0c;哨兵集群等&#xff0c;本节我们搭建一主二从的多Redis架构。 redis主从安装1主2从的方式配置&#xff0c;以端口号为redis的主从文件夹。 主…

CSS 文字弹跳效果

鼠标移过去 会加快速度 <template><div class"bounce"><p class"text" :style"{animationDuration: animationDuration}">欢迎使用UniApp Vue3&#xff01;</p></div> </template><script> export d…

Java架构师系统架构设计实践

目录 1 导语2 架构设计实践本章概述3 架构设计要素概述和规划4 架构设计模式5 架构设计输入6 架构设计输出7 架构设计要素总结 想学习架构师构建流程请跳转&#xff1a;Java架构师系统架构设计 1 导语 Java架构师在进行系统架构设计时&#xff0c;需要综合考虑多个方面&#…

【三维生成】稀疏重建、Image-to-3D方法(汇总)

系列文章目录 总结一下近5年的三维生成算法&#xff0c;持续更新 文章目录 系列文章目录一、LRM&#xff1a;单图像的大模型重建&#xff08;2023&#xff09;摘要1.前言2.Method3.实验 二、SSDNeRF&#xff1a;单阶段Diffusion NeRF的三维生成和重建&#xff08;ICCV 2023&am…

【网络安全 | 网络协议】结合Wireshark讲解TCP三次握手

前言 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的传输层协议。在建立 TCP 连接时&#xff0c;需要进行三次握手&#xff0c;防止因为网络延迟、拥塞等原因导致的数据丢失或错误传输&#xff0c;确保双方都能够正常通信。 TCP三次握手在Wireshark数据包中…

线程学习(3)-volatile关键字,wait/notify的使用

​ &#x1f495;"命由我作&#xff0c;福自己求"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;线程学习(2)​​​​ 一.volatile关键字 volatile关键字是多线程编程中一个非常重要的概念&#xff0c;它主要有两个功能&#xff1a;保证内存可见性…