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.mzph.cn/news/579224.shtml

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

相关文章

15.权限控制 + 置顶、加精、删除

目录 1.权限控制 1.1 登录检查 1.2 授权配置 1.3 认证方案 1.4 CSRF 配置 2.置顶、加精、删除 2.1 开发数据访问层 2.2 业务层 2.3 表现层 Spring Security 是一个专注于为 Java 应用程序提供身份认证和授权的框架&#xff0c;它的强大之处在于它可以轻松扩展以满足自…

蓝桥杯的学习规划

c语言基础&#xff1a; Python语言基础 学习路径&#xff1a;画框的要着重学习

一文读懂SoBit 跨链桥教程

从BTC网络到Solana网络桥接BRC20 1.打开SoBit平台&#xff1a;在您的网络浏览器中启动SoBit Bridge应用程序。 2.连接您的钱包&#xff1a; 选择SoBit界面右上角的比特币网络来连接您的数字钱包。 3.选择源链、目标链和您想桥接的代币&#xff1a; 从下拉菜单中选择’BTC’作为…

翻硬币C语言

分析&#xff1a;首先&#xff0c;我们如果想要使得两次的硬币可以转化&#xff0c;那么两组字符对应不同的的个数就只能是偶数&#xff0c;比如&#xff1a; * * * * * o o * * * * * 我们要对上面的例子翻动5次&#xff0c;我们可以看出两个不同的位置相差五个单位&#x…

用C/C++实现MSML协议栈的详细介绍

一、MSML协议简介 MSML&#xff08;Media Server Markup Language&#xff09;是一种基于XML的标记语言&#xff0c;用于控制媒体服务器。它是媒体服务器控制协议的一种&#xff0c;允许第三方应用与媒体服务器进行交互&#xff0c;实现对媒体流的创建、修改和释放等操作。MSM…

Netty—Reactor线程模型详解

文章目录 前言线程模型基本介绍线程模型分类Reactor线程模型介绍Netty线程模型&#xff1a; 传统阻塞IO的缺点Reactor线程模型单Reactor单线程模式单Reactor多线程模式主从Reactor多线程Reactor 模式小结 Netty 线程模型案例说明&#xff1a;Netty核心组件简介ChannelPipeline与…

Linux中Mysql数据库备份操作

逻辑备份 备份的是建表、建库、插入等操作所执行SQL语句&#xff0c;适用于中小型数据库&#xff0c;效率相对较低。 本质&#xff1a;导出的是SQL语句文件 优点&#xff1a;不论是什么存储引擎&#xff0c;都可以用mysqldump备成SQL语句 缺点&#xff1a;速度较慢&#xff0c;…

Centos7安装Docker和Docker-Compose

环境 操作系统&#xff1a;Centos 7.9 root环境 Docker安装 卸载原先的Docker环境 如果你先前的操作系统安装了Docker环境&#xff0c;请卸载 Docker 相关的软件包&#xff0c;没有则忽略这一步。 yum remove docker \docker-client \docker-client-latest \docker-common \doc…

(2021|CVPR,XMC-GAN,对比学习,注意力自调制)用于文本到图像生成的跨模态对比学习

Cross-Modal Contrastive Learning for Text-to-Image Generation 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 3. 基础 4. 方法 4.1 用于文本到图像…

【软件工程】可执行文件和数据分离

一、概述 可执行文件和数据分离是一种软件设计策略&#xff0c;旨在将程序代码和程序使用的数据分离存储。这种方法通常用于提高软件的模块化程度和灵活性&#xff0c;以及方便软件的管理和维护。 在可执行文件和数据分离中&#xff0c;程序代码通常以可执行文件的形式存储&a…

Java小案例-Sentinel的实现原理

前言 Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。 主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 核心概念 要想理解一个新的技…

unityc用vs2017介绍

21版unity能用17vs&#xff0c;只要在unity的Edit/Preferences/ExternalTools里面改既可。

音频修复增强软件iZotope RX 10 mac特点介绍

iZotope RX 10 mac是一款音频修复和增强软件。 iZotope RX 10 mac软件特点 声音修复&#xff1a;iZotope RX 10可以去除不良噪音、杂音、吱吱声等&#xff0c;使音频变得更加清晰干净。 音频增强&#xff1a;iZotope RX 10支持对音频进行音量调节、均衡器、压缩器、限制器等处…

SpringSecurity6 | 登录失败后的JSON处理

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringSecurity6 ✨特色专栏: MySQL学习 🥭本文内容: SpringSecurity6 | 登录失败后的JSON处理 📚个人知识库: Leo知识库,…

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

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

SAP PP 配置学习(二)

MRP 参数文件设定 扩允物料视图 删除物料 物料批量维护

【C Primer Plus第六版 学习笔记】第十四章 结构和其他数据形式

有基础&#xff0c;进阶用&#xff0c;个人查漏补缺 建立结构声明&#xff1a;描述该对象由什么组成&#xff0c;即结构布局 格式&#xff1a; 关键字 标记&#xff08;可选&#xff09;{结构 }&#xff1b; 举例&#xff1a; struct book{char title[2];char author[4];float …

欧洲影像学人工智能和影像组 学文章审稿指南解读(一)--本手稿是否专注于AI/影像组学的报告?

欧洲影像学人工智能和影像组 学文章审稿指南解读 针对人工智能&#xff08;AI&#xff09;和影像组学领域的研究文章&#xff0c;欧洲影像学&#xff08;European Radiology&#xff09;期刊为审稿人提出了一系列特别的说明和要求。这些要求不仅仅是审稿的准则&#xff0c;更是…

Git 查询某段时间所有用户提交的代码量并过滤文件格式

获取代码提交用户 git log --format%aN| sort -u | while read name; do echo -en "$name\t"; done;获取代码提交文件的修改情况 git log --authorforwardhuan --prettytformat: --numstat获取代码提交文件的修改情况(过滤文件类型) git log --authorforwardhuan …

使用TLS/SSL Pinning保护安卓应用程序

使用TLS/SSL Pinning保护安卓应用程序 在现代术语中&#xff0c;“SSL”&#xff08;安全套接层&#xff09;通常指的是“TLS”&#xff08;传输层安全&#xff09;。虽然 SSL 和 TLS 不是同一个东西&#xff0c;但 TLS 是 SSL 的改进和更安全的版本&#xff0c;并且在实践中已…