Spring Security 中自定义权限表达式

Spring Security 中自定义权限表达式

    • 一. SpEL中使用自定义Bean
    • 二. 通过类继承自定义权限表达式
      • 2.1 自定义 ExpressionRoot
    • 三. 参考文章

前言

这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱

一. SpEL中使用自定义Bean

通过编程授权方法

首先,声明一个 Bean,如下所示:

@Service("authz")
public class PermissionService {/*** 验证用户是否具备某权限** @param permission 权限字符串* @return 用户是否具备某权限*/public boolean hasPerm(String permission) {// 逻辑处理}}

然后,在注解中以如下方式引用该 Bean:

@Controller
public class MyController {@PreAuthorize("@authz.hasPerm('com:user:ip')")@GetMapping("/endpoint")public String endpoint() {// ...}
}

Spring Security 将在每次方法调用时调用该Bean上的给定方法。

这样做的好处是所有的授权逻辑都在一个单独的类中,可以独立进行单元测试并验证其正确性。

二. 通过类继承自定义权限表达式

  1. 第一种的缺点:

    (1) 使用第一种方式idea会有告警,使得项目很难看

    请添加图片描述

    (2) 这种自定义方式太自由了,没有在 Spring Security 架构内完成这件事。所以,我们要在不使用第三方对象的情况下,来自定义一个权限判断的表达式。

我们在 @PreAuthorize 注解中使用的不用加对象名就能调用的授权字段和方法,如 hasAuthority、hasPermission、hasRole、hasAnyRole 等, Spring Security 将所有授权字段和方法封装在一组根(root)对象中。最通用的根对象称为 SecurityExpressionRoot,它构成了 MethodSecurityExpressionRoot 的基础。当准备评估授权表达式时,Spring Security 会将该根对象提供给 MethodSecurityEvaluationContext

2.1 自定义 ExpressionRoot

首先我们自定义一个类继承自 SecurityExpressionRoot 并实现 MethodSecurityExpressionOperations 接口(本来直接继承自 MethodSecurityExpressionRoot 即可,但是因为这个类不是 public 的,没法继承,所以我们就实现 MethodSecurityExpressionOperations 接口即可):

/*** 自定义权限实现** @author chenyunzhi*/
public class PermissionSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {private Object filterObject;private Object returnObject;private Object target;/*** 所有权限标识*/private static final String ALL_PERMISSION = "*:*:*";private static final String PERMISSION_DELIMETER = ",";/*** Creates a new instance** @param authentication the {@link Authentication} to use. Cannot be null.*/public PermissionSecurityExpressionRoot(Authentication authentication) {super(authentication);}/*** 验证用户是否具备某权限** @param permission 权限字符串* @return 用户是否具备某权限*/public boolean hasPerm(String permission) {if (StringUtils.isEmpty(permission)) {return false;}LoginUser loginUser = SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {return false;}return hasPermissions(loginUser.getPermissions(), permission);}/*** 验证用户是否具有以下任意一个权限** @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表* @return 用户是否具有以下任意一个权限*/public boolean hasAnyPerm(String permissions) {if (StringUtils.isEmpty(permissions)) {return false;}
//        LoginUser loginUser = SecurityUtils.getLoginUser();LoginUser loginUser = SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {return false;}Set<String> authorities = loginUser.getPermissions();for (String permission : permissions.split(PERMISSION_DELIMETER)){if (permission != null && hasPermissions(authorities, permission)){return true;}}return false;}/*** 判断是否包含权限** @param permissions 权限列表* @param permission  权限字符串* @return 用户是否具备某权限*/private boolean hasPermissions(Set<String> permissions, String permission) {return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));}@Overridepublic void setFilterObject(Object filterObject) {this.filterObject = filterObject;}@Overridepublic Object getFilterObject() {return this.filterObject;}@Overridepublic void setReturnObject(Object returnObject) {this.returnObject = returnObject;}@Overridepublic Object getReturnObject() {return this.returnObject;}@Overridepublic Object getThis() {return this.target;}
}

Spring Security 中,MethodSecurityExpressionRoot 的配置是通过 DefaultMethodSecurityExpressionHandler 来完成的,现在我们自定义了 PermissionSecurityExpressionRoot, 所以,再来一个PermissionSecurityExpressionHandler类继承DefaultMethodSecurityExpressionHandler,如下:

/*** @author chenyunzhi* @description: 定义handler配置 PermissionSecurityExpressionRoot*/
@Component
public class PermissionSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {@Overrideprotected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {PermissionSecurityExpressionRoot root = new PermissionSecurityExpressionRoot(authentication);root.setTrustResolver(getTrustResolver());root.setPermissionEvaluator(getPermissionEvaluator());root.setRoleHierarchy(getRoleHierarchy());return root;}
}

然后就可以通过以下注解使用了

@PreAuthorize("hasPerm('com:user:add')")

三. 参考文章

如何在 Spring Security 中自定义权限表达式

security中文文档

作者:神的孩子都在歌唱
本人博客:https://blog.csdn.net/weixin_46654114
转载说明:务必注明来源,附带本人博客连接。

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

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

相关文章

Linux学习第27天:Platform设备驱动开发(一): 专注与分散

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 专注与分散是我在题目中着重说明的一个内容。这是今天我们要学习分离与分层概念的延伸。专注是说我们要专注某层驱动的开发&#xff0c;而对于其他层则是芯片厂商…

robot framework导入库和资源

robot framework导入库和资源 一 导入系统库和第三方库&#xff08;Library&#xff09;二 导入自己写的py文件三 建立资源作为关键字3.1 创建资源3.2 在资源里创建用户关键字3.3 使用用户关键字 四 将自己写的py文件中类的函数作为关键字4. 1编写py文件&#xff0c;文件名和里…

搭建VM虚拟机+Centos7 Oracle版 + 配置ssh + Xftp + secureCRT

文章目录 1 视频地址1.1 基本参数1.2 ISO下载地址&#xff1a;1.3 开启ssh1.3.1 使用root用户进行1.3.2 修改ssh配置1.3.3 关闭 SELINUX 2 查询虚拟机的ip2.1 联网2.2 桌面打开终端查询虚拟机ip 3 连接Xftp4 连接SecureRT 1 视频地址 01-搭建VM虚拟机Centos7 Oracle版 配置ss…

计算机网络-IP地址

文章目录 子网划分定长子网划分子网划分的方法子网掩码 可变长子网划分 无类别编址网络前缀路由聚合 特殊用途的IP地址专用网络地址链路本地地址运营商级NAT共享地址用于文档的测试网络地址 IP地址的规划和分配IP地址的规划和分配方法IP地址的规划和分配实例 子网划分 定长子网…

基于未来搜索算法的无人机航迹规划-附代码

基于未来搜索算法的无人机航迹规划 文章目录 基于未来搜索算法的无人机航迹规划1.未来搜索搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用未来搜索算法来优化无人机航迹规划。 …

装备制造行业云MES解决方案

一、装备制造行业发展现状&#xff1a; 机械制造业主要是通过对金属原材料物理形状的改变、加工组装进而成为产品。机械制造业生产的主要特点是&#xff1a;离散为主、流程为辅、装配为重点。 工业生产基本上分为两大方式&#xff1a; 1.离散型&#xff1a;离散型是指以一个…

《数据安全与流通:技术、架构与实践》新书发布

随着数据成为关键生产资料和要素&#xff0c;国内外数据安全相关的法律法规在快速完善&#xff0c;数据安全技术也在快速发展。5月25-26日&#xff0c;由星环科技、上海数据交易所、上海大数据联盟、财联社联合主办的向星力未来数据技术峰会 &#xff08;FDTC&#xff09;上&am…

C#__委托delegate

委托存储的是函数的引用&#xff08;把某个函数赋值给一个委托类型的变量&#xff0c;这样的话这个变量就可以当成这个函数来进行使用了&#xff09; 委托类型跟整型类型、浮点型类型一样&#xff0c;也是一种类型&#xff0c;是一种存储函数引用的类型 using System.Reflec…

目标检测理论知识

目标检测 1.基本概念 目标检测&#xff08;Object Detection&#xff09;的任务是找出图像中所有感兴趣的目标&#xff08;物体&#xff09;&#xff0c;确定它们的类别和位置&#xff0c;是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态&#xff0c;…

安装最新版vue-cli,并搭建一个vue2项目

安装最新版vue-cli&#xff0c;并搭建一个vue2项目 卸载旧版本环境 卸载node.js 可以使用qq电脑管家&#xff0c;找到nodejs卸载即可 cmd查看vue cli版本&#xff08;可以看到我们是vue cli 2.x&#xff09; C:\Users\youzhengjie666> vue -V 2.9.6卸载vue cli 2.x np…

CMake:构建时为特定目标运行自定义命令

CMake&#xff1a;构建时为特定目标运行自定义命令 导言项目结构相关源码结果 导言 add_custom_command 是 CMake 中用于添加自定义构建规则的命令&#xff0c;通常用于在编译项目时执行一些自定义操作&#xff0c;例如生成文件、运行脚本等。 项目结构 . ├── CMakeLists…

VMware虚拟网络连接的三种方式

桥接模式(Bridged) 什么是桥接模式?桥接模式就是将主机网卡与虑拟机虑拟的网卡利用虑拟网桥进行通信。在桥接的作用下&#xff0c;类似于把物理主机虑拟为一个交换机&#xff0c;所有桥接设置的虚拟机连接到这个交换机的一个接口上&#xff0c;物理主机也同样插在这个交换机当…

IDEA MyBatisX插件介绍

一、前言 前几年写代码的时候&#xff0c;要一键生成DAO、XML、Entity基础代码会采用第三方工具&#xff0c;比如mybatis-generator-gui等&#xff0c;现在IDEA或Eclipse都有对应的插件&#xff0c;像IDEA中MyBatisX就是一个比较好用的插件。 二、MyBatisX安装配置使用 MyBa…

HTML光速入门----(有这一篇就够了~!)

前言 因为是博主的平时自己的笔记所以截图和写的方式有点随意&#xff0c;还请大家多多谅解&#xff0c;有什么不对的地方&#xff0c;可以直接在评论区指出问题&#xff0c;感谢大家的指点和阅读我的文章 如果需要这里面演示的html&#xff0c;可以私信我&#xff0c;我会统一…

[黑马程序员Pandas教程]——Pandas快速体验

目录&#xff1a; 为什么要使用Python做数据开发Python在数据开发领域的优势为什么要学习Pandas其他常用Python库介绍主要内容介绍Anaconda安装Anaconda的虚拟环境管理虚拟环境的作用可以通过Anaconda界面创建虚拟环境通过命令行创建虚拟环境通过Anaconda管理界面安装包也可以…

Web3 React项目Dapp获取智能合约对象

上文Web3 整理React项目 导入Web3 并获取区块链信息中&#xff0c;我们在react搭建的dapp中简单拿到了我们区块链中的账号授权信息 那 我们继续 先终端运行 ganache -d将ganache环境起起来 然后 我们运行 dapp 拿到授权列表 回到上文结束的一个状态 然后 我们发布一下自己的…

【设计模式】第22节:行为型模式之“状态模式”

一、简介 状态模式一般用来实现状态机&#xff0c;而状态机常用在游戏、工作流引擎等系统开发中。不过&#xff0c;状态机的实现方式有多种&#xff0c;除了状态模式&#xff0c;比较常用的还有分支逻辑法和查表法。该模式允许对象内部状态改变使改变它的行为。 二、适用场景…

「Qt中文教程指南」如何创建基于Qt Widget的应用程序(四)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文描述了如何使用…

如何选一个质量好的超声波清洗机、超声波清洗机推荐

超声波清洗机的品牌这么多&#xff0c;到底该如何选择一个质量好的超声波清洗机呢&#xff1f;其实选购超声波清洗机还是有讲究的&#xff0c;并非说说超声波清洗机越贵就是越好的&#xff0c;入手之前还是需要多看一下参数之类的&#xff0c;不然容易买回来后悔&#xff0c;作…

dash--项目的前端展示简单基础

1.前置工作 创建虚拟环境&#xff1a; sudo apt-get install python3-venv # 安装 python3 -m venv venv # 在本目录下创建venv虚拟环境&#xff08;也是一个文件夹。如果用不到这个虚拟环境以后就rm -rf venv&#xff09; source venv/bin/activate # 激活虚拟环境临时使用清华…