梳理一下若依框架的权限过滤系统

梳理一下若依框架的权限过滤系统

在这里插入图片描述

首先,我们直入主题,且看这段代码

/**
 * 获取用户列表
 */
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user)
{
    startPage();
    List<SysUser> list = userService.selectUserList(user);
    return getDataTable(list);
}

可以看到哈

@PreAuthorize(“@ss.hasPermi(‘system:user:list’)”)

对的,就是这一行啦,这一行很重要!这是主要的权限过滤入口

我们暂且先不去直接分析怎么实现的,我们猜一下,这个会是怎么实现的:

这段代码看起来是使用了Spring Security中的@PreAuthorize注解,该注解通常用于方法级别的访问控制。具体来说,这段代码表明了一个方法或者类中的某个方法需要用户在执行之前满足特定的权限。

分解一下这段代码:

  • @PreAuthorize注解表示在方法执行之前进行权限验证。
  • "@ss.hasPermi('system:user:list')"是权限表达式,它指定了所需的权限。这里的权限表达式看起来是Spring Security中自定义的,可能涉及到系统用户列表的权限。

猜测的作用是,只有具有'system:user:list'权限的用户才能执行标记有该注解的方法。这可能是用于限制对系统用户列表相关操作的访问权限,确保只有授权的用户能够执行这些操作。

请注意,有一次提到了了一个名词Spring Security,先生大名相比耳熟能详,我们就再说一下先生吧

https://springdoc.cn/spring-security/servlet/authorization/method-security.html#use-preauthorize 中文文档

Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。【官网介绍】

目前我们可能接触的有两种安全框架,一种就是大而丰富的Spring Security,一种就是小而精巧的shiro

这里不多废话,我们主要是研究若依怎么实现的权限过滤,我们就接着聊

首先,现在我们可以确定一件事,若依使用的Spring Security框架!

紧接着,我们再看看若依自己封装的hasPermi

package com.ruoyi.framework.web.service;

import java.util.Set;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.security.context.PermissionContextHolder;

/**
 * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母
 * 
 * @author ruoyi
 */
@Service("ss")
public class PermissionService
{
    /**
     * 验证用户是否具备某权限
     * 
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean
    hasPermi(String permission)
    {
        if (StringUtils.isEmpty(permission))
        {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        PermissionContextHolder.setContext(permission);
        return hasPermissions(loginUser.getPermissions(), permission);
    }

    /**
     * 验证用户是否不具备某权限,与 hasPermi逻辑相反
     *
     * @param permission 权限字符串
     * @return 用户是否不具备某权限
     */
    public boolean lacksPermi(String permission)
    {
        return hasPermi(permission) != true;
    }

    /**
     * 验证用户是否具有以下任意一个权限
     *
     * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
     * @return 用户是否具有以下任意一个权限
     */
    public boolean hasAnyPermi(String permissions)
    {
        if (StringUtils.isEmpty(permissions))
        {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        PermissionContextHolder.setContext(permissions);
        Set<String> authorities = loginUser.getPermissions();
        for (String permission : permissions.split(Constants.PERMISSION_DELIMETER))
        {
            if (permission != null && hasPermissions(authorities, permission))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断用户是否拥有某个角色
     * 
     * @param role 角色字符串
     * @return 用户是否具备某角色
     */
    public boolean hasRole(String role)
    {
        if (StringUtils.isEmpty(role))
        {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
        {
            return false;
        }
        for (SysRole sysRole : loginUser.getUser().getRoles())
        {
            String roleKey = sysRole.getRoleKey();
            if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 验证用户是否不具备某角色,与 isRole逻辑相反。
     *
     * @param role 角色名称
     * @return 用户是否不具备某角色
     */
    public boolean lacksRole(String role)
    {
        return hasRole(role) != true;
    }

    /**
     * 验证用户是否具有以下任意一个角色
     *
     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
     * @return 用户是否具有以下任意一个角色
     */
    public boolean hasAnyRoles(String roles)
    {
        if (StringUtils.isEmpty(roles))
        {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
        {
            return false;
        }
        for (String role : roles.split(Constants.ROLE_DELIMETER))
        {
            if (hasRole(role))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否包含权限
     * 
     * @param permissions 权限列表
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission)
    {
        return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }
}

这是一个自定义权限服务类,用于在应用中进行权限控制。以下是对代码的解释和分析:

  1. hasPermi 方法

    • 该方法用于验证用户是否具备某个权限。
    • 获取当前登录用户信息通过 SecurityUtils.getLoginUser(),并检查用户是否为空以及是否有权限信息。
    • 将权限字符串设置到 PermissionContextHolder 中,可能用于在其他地方获取当前权限信息。
    • 最终调用 hasPermissions 方法判断用户是否具有指定的权限。
  2. lacksPermi 方法

    • 该方法是 hasPermi 方法的逻辑相反,用于验证用户是否不具备某个权限。
  3. hasAnyPermi 方法

    • 该方法用于验证用户是否具备多个权限中的任意一个。
    • 通过分隔符 Constants.PERMISSION_DELIMETER 将多个权限字符串分隔成数组,并逐一判断用户是否具备这些权限。
  4. hasRole 方法

    • 该方法用于验证用户是否具备某个角色。
    • 获取当前登录用户信息,检查用户是否为空以及是否具有角色信息。
    • 遍历用户的角色列表,判断是否具有指定的角色。
  5. lacksRole 方法

    • 该方法是 hasRole 方法的逻辑相反,用于验证用户是否不具备某个角色。
  6. hasAnyRoles 方法

    • 该方法用于验证用户是否具备多个角色中的任意一个。
    • 通过分隔符 Constants.ROLE_DELIMETER 将多个角色字符串分隔成数组,并逐一判断用户是否具备这些角色。
  7. hasPermissions 方法

    • 该方法用于判断用户是否具备某个权限。
    • 如果用户具备 Constants.ALL_PERMISSION 权限,或者用户的权限列表中包含指定的权限,则返回 true

这个服务类的作用是简化在代码中进行权限验证的逻辑,通过提供这些方法,可以更方便地进行权限控制。例如,在方法上使用 @PreAuthorize("@ss.hasPermi('system:user:list')") 注解时,实际上会调用 PermissionService 中的 hasPermi 方法来进行权限验证。

在这里呢,提到了PermissionContextHolder这个方法,其实就是一个上下文

public class PermissionContextHolder
{
    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";

    public static void setContext(String permission)
    {
        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
                RequestAttributes.SCOPE_REQUEST);
    }

    public static String getContext()
    {
        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
                RequestAttributes.SCOPE_REQUEST));
    }
}
  1. PermissionContextHolder 类用于在应用程序中的不同部分传递和存储权限信息。
  2. setContext 方法用于设置权限信息,它接受一个表示权限的字符串参数,并将该权限信息存储在当前请求的属性中,作用范围为请求级别(RequestAttributes.SCOPE_REQUEST)。
  3. getContext 方法用于获取权限信息,它从当前请求的属性中检索之前设置的权限信息,并将其作为字符串返回。
  4. 这里使用了RequestContextHolder.currentRequestAttributes()来获取当前请求的属性,这是Spring框架提供的一种方便的方式,可以在应用程序中获取与当前请求相关的属性。
  5. PERMISSION_CONTEXT_ATTRIBUTES 是一个常量,表示权限信息在请求属性中的键名。

这段代码提供了一个简单的权限上下文管理工具,使得在应用中能够方便地设置和获取权限信息,通常在处理请求时,可以使用这些工具方法来确保在请求处理过程中能够方便地传递和获取权限信息。

最后总结

梳理一下若依框架的权限过滤系统:

  1. 权限注解

    • 在若依框架中,使用了Spring Security提供的 @PreAuthorize 注解来进行方法级别的访问控制。
    • 例如:@PreAuthorize("@ss.hasPermi('system:user:list')") 表示只有具有 'system:user:list' 权限的用户才能执行标记有该注解的方法。这个字符串是前端传递的。
  2. 自定义权限服务类 (PermissionService):

    • 该类封装了一系列方法,用于在代码中方便地进行权限验证。
    • 提供了对单一权限、多个权限、角色的验证方法,以及这些验证方法的逻辑相反的方法。
    • 通过调用 SecurityUtils.getLoginUser() 获取当前登录用户信息,并通过 PermissionContextHolder 存储和获取权限信息。
    • 通过设置权限信息到上下文,实现在代码中不同地方方便地获取当前请求的权限信息。
  3. 权限上下文管理工具 (PermissionContextHolder):

    • 用于在应用程序中传递和存储权限信息。
    • 提供了 setContext 方法用于设置权限信息,以及 getContext 方法用于获取权限信息。
    • 使用了 RequestContextHolder.currentRequestAttributes() 来获取当前请求的属性,作用范围为请求级别。
  4. 权限字符串解析

    • 权限字符串是以 'system:user:list' 这样的格式表示的,其中 'system' 为系统名称,'user' 为模块名称,'list' 为操作名称。这样的权限字符串形式有助于细粒度地控制权限。
  5. Spring Security框架

    • 若依框架使用了Spring Security作为权限框架,通过配置和注解的方式实现了权限控制。
    • Spring Security提供了强大的身份验证和访问控制机制,可以通过配置文件或注解的方式定义权限规则。

若依框架通过结合Spring Security、自定义权限服务类和权限上下文管理工具,实现了一套灵活且方便集成的权限过滤系统。这样的设计使得在代码中可以通过简单的注解和方法调用实现权限控制,提高了开发效率。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony当前进展和未来趋势

操作系统自20世纪50年代诞生&#xff0c;经历了从专用操作系统到通用操作系统的转变。整体可以将操作系统的发展历史分为3个阶段&#xff1a;PC时代、移动互联网时代、万物互联时代。 PC时代主要以计算机为主&#xff0c;用户规模从1970年的10亿增长到1990年的30亿。这一时代诞…

QComboBox 下拉框

文章目录 1、简介2、functions3、Signal QT 官方文档参考地址&#xff1a;https://doc.qt.io/qt-5/qcombobox.html 1、简介 QComboBox 是下拉列表框组件类&#xff0c;它提供一个下拉列表供用户选择&#xff0c;也可以直接当作一个 QLineEdit 用作输入。 2、functions 1、voi…

供应商导添加预扣税字段

文章目录 1 Introduction2 Code3 Summary 1 Introduction I only think I can assign value to them and I implement it by the following code . 2 Code LOOP AT gt_bukrs INTO gs_bukrs WHERE lifnr gs_alv1-lifnr.CLEAR:ls_company.ls_company-task M.ls_company-data…

mybatis----动态Sql

1.if标签 通过if标签构建动态条件&#xff0c;通过其test属性的true或false来判断该添加语句是否执行。 mapper接口 public interface AccountMapper {List<Account> selectAllByCondition(Account account); } 映射文件 <select id"selectAllByCondition&q…

具有运动模糊的大规模场景的混合神经绘制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;具有运动模糊的大规模场景的混合神经绘制1、研究背景2、方法提出3、视点依赖归一化方法4、训练方法5、试验细节及对比 YOLO模型1、…

.NET高速开发分层架构,ASPNETCore,IOC开发

分层架构,ASPNETCore,IOC开发 大家好,我是行不更名,坐不改姓的宋晓刚。今天我将带领大家深入了解分层架构、ASP.NET Core、IoC 开发,以及共同开发的魅力。我们将一同探索如何利用这些先进技术构建高效、可维护的数据库应用程序。 家人们,如果有什么不懂,可以留言,或者…

【JS逆向学习】国家加密系列-SM算法实例

SM系列 1、国家加密算法介绍 事实上从 2010 年开始&#xff0c;我国国家密码管理局就已经开始陆续发布了一系列国产加密算法&#xff0c;其中SM1、SM4、SM7、祖冲之密码&#xff08;ZUC&#xff09;是对称算法&#xff1b;SM2、SM9是非对称算法&#xff1b;SM3是哈希算法。目…

大数据导论(4)---大数据应用

文章目录 1. 在互联网中的应用1.1 推荐系统1.2 长尾理论1.3 推荐方法与模型1.4 推荐系统应用 2. 在其他领域的应用2.1 企业营销2.2 智慧交通 1. 在互联网中的应用 1.1 推荐系统 1. 推荐系统产生&#xff1a;  (1) 互联网的飞速发展使我们进入了信息过载的时代&#xff0c;搜索…

二叉树题目:二叉树的序列化与反序列化

文章目录 题目标题和出处难度题目描述要求示例数据范围 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树的序列化与反序列化 出处&#xff1a;297. 二叉树的序列化与反序列化 难度 8 级 题目描述 要求 序列…

数据结构:堆与堆排序

目录 堆的定义&#xff1a; 堆的实现&#xff1a; 堆的元素插入&#xff1a; 堆元素删除&#xff1a; 堆初始化与销毁&#xff1a; 堆排序&#xff1a; 堆的定义&#xff1a; 堆是一种完全二叉树&#xff0c;完全二叉树定义如下&#xff1a; 一棵深度为k的有n个结点的二…

微信小程序的nodejs+vue课堂在线学习系统教学辅助平台PHP设计与实现

小程序主要实现功能&#xff1a;一、用户的登录与实现 二、课程页面。学生们可以观看课程视频【课程视频有章程】&#xff0c;搜索课程&#xff0c;课程签到&#xff0c;评论课程&#xff0c;课后答题&#xff08;课后成绩&#xff09;&#xff0c;课程互动&#xff08;在视频下…

【深度学习】手把手教你使用 Auto DL 远程服务器连接 PyCharm

前言 文章性质&#xff1a;实操记录 &#x1f4bb; 主要内容&#xff1a;主要记录了如何租用 Auto DL 服务器&#xff0c;以及如何在 PyCharm 中连接远程服务器。 相关文档&#xff1a;如何使用 Auto DL 远程服务器连接 PyCharm 运行代码 - 知乎 冷知识1&#xff1a;小伙伴们不…

c++:string相关的oj题(把字符串转换成整数、344.反转字符串、387. 字符串中的第一个唯一字符、917. 仅仅反转字母)

文章目录 1.把字符串转换成整数题目详情代码思路 2. 344.反转字符串题目详情代码1思路1代码2思路 3. 387. 字符串中的第一个唯一字符题目详情代码思路 4. 917. 仅仅反转字母题目详情代码思路 1.把字符串转换成整数 传送门 题目详情 代码 class Solution { public:int StrToI…

提升用户体验的利器——TTS语音合成软件盘点

提升用户体验的利器——TTS语音合成软件盘点 在当今信息爆炸的时代&#xff0c;人们每天都要处理大量的文本信息。因此&#xff0c;将文本信息转化为语音信息&#xff0c;使得信息能够以更自然、更方便的方式传达给人们&#xff0c;就显得尤为重要。这就是TTS&#xff08;Text…

【C++修行之道】竞赛常用库函数(sort,min和max函数,min_element和max_element、nth_element)

目录 一、sort 1.1sort简介 语法 参数 功能 适用容器 1.2sort的用法 1.3自定义比较函数 示例 1265蓝桥题 —— 排序 二、min和max函数 三、min_element和max_element 497蓝桥题 —— 成绩分析 四、nth_element 一、sort 1.1sort简介 sort函数包含在头文件<a…

手机软件的测试主要有哪些方面去测试,性能测试用什么去测试好?

手机App软件与Web软件系统的架构是不一样的&#xff0c;手机是基于CS架构&#xff0c;而Web系统是基于BS架构的&#xff0c;所以测试手机App软件那么要考虑的东西会更多一些。 分析题主的问题包含两块&#xff1a; 1、手机软件(App)测试主要有哪些方面&#xff1f; 2、手机软件…

【C/C++】C/C++编程——为什么学习 C++?

当提到C的时候&#xff0c;很多人会觉得语法复杂、学习曲线陡峭&#xff0c;并且好像与C语言还有点"纠缠不清"。尽管如此&#xff0c;C仍然是当今世界上最受欢迎和最有影响力的编程语言之一。特别是在当今快速发展的人工智能&#xff08;AI&#xff09;领域&#xff…

java数据结构与算法刷题-----LeetCode645. 错误的集合(位运算解法需要重点掌握)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 法一&#xff1a;桶排序思想法二&#xff1a;位运算 法一&#x…

gdip-yolo项目解读:gdip模块 |mdgip模块 |GDIP regularizer模块的使用分析

gdip-yolo是2022年提出了一个端到端的图像自适应目标检测框架&#xff0c;其论文中的效果展示了良好的图像增强效果。其提出了gdip模块 |mdgip模块 |GDIP regularizer模块等模块&#xff0c;并表明这是效果提升的关键。为此对gdip-yolo的项目进行深入分析。 gdip-yolo的论文可以…

ARM 驱动 1.22

linux内核等待队列wait_queue_head_t 头文件 include <linux/wait.h> 定义并初始化 wait_queue_head_t r_wait; init_waitqueue_head(&cm_dev->r_wait); wait_queue_head_t 表示等待队列头&#xff0c;等待队列wait时&#xff0c;会导致进程或线程被休眠&…