Security方法注解权限控制过程及自定义权限表达式
文章目录
- 使用内置的权限表达式
- @PreAuthorize
- PermissionEvaluator
- 自定义权限表达式
- SysMethodSecurityExpressionHandler
- 源码流程
- SysMethodSecurityExpressionRoot
使用内置的权限表达式
@PreAuthorize
这个用来判断超级管理员的话,还得在表达式上加上或
PermissionEvaluator
本来是想定义一个 PermissionEvaluator,但是发现,写表达式的时候,还得弄2个参数,@PreAuthorize(‘/admin/user/list’,‘user:list’),有点麻烦
package com.zzhua.blog.config.security.auth;import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;import java.io.Serializable;// GlobalMethodSecurityConfiguration 在 afterSingletonsInstantiated 方法中,// 会去容器中寻找 PermissionEvaluator 的bean, 设置到 defaultMethodExpressionHandler 中,// 并且定义了一个 PreInvocationAuthorizationAdvice 的bean, 将刚刚的设置到 defaultMethodExpressionHandler 设置给了这个Advice,//// GlobalMethodSecurityConfiguration 并且定义了aop中的 methodSecurityInterceptor(),会去创建访问决策管理器,// 访问决策管理器会去添加投票器,里面会创建一个 PreInvocationAuthorizationAdviceVoter, 里面会传入上面定义的Advice,//// 所以接下来的流程看这个拦截器就行了,同时,也离不开 MethodSecurityMetadataSourceAdvisor 切面的支持 因此,方法鉴权就是基于Aop的实现,// 用法参考:SpringBoot 整合SpringSecurity示例实现前后分离权限注解+JWT登录认证-https://juejin.cn/post/6844903974546456590#heading-4
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {@Overridepublic boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {return false;}@Overridepublic boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {return false;}
}
自定义权限表达式
(也可以采用若依的方法,自定义权限表达式,其实就是利用了el表达式,但是通过自定义权限表达式的过程,可以更加清楚security处理方法注解权限时的整个处理过程,我们也可以在这里扩展一些权限通配符匹配的功能)
SysMethodSecurityExpressionHandler
可参考:如何在 Spring Security 中自定义权限表达式
源码流程
此handler 将会被注入到 GlobalMethodSecurityConfiguration#setMethodSecurityExpressionHandler 作为 handler
GlobalMethodSecurityConfiguration 定义了一个 PreInvocationAuthorizationAdvice 的bean, 获取并设置了上面定义的 handler
GlobalMethodSecurityConfiguration 并且定义了aop中的 methodSecurityInterceptor()拦截器,会去创建访问决策管理器
访问决策管理器会去添加投票器(当然,不止这一种投票器),会创建一个 PreInvocationAuthorizationAdviceVoter, 里面会传入上面定义的Advice,
@EnableWebSecurity引入了一个 MethodSecurityMetadataSourceAdvisorRegistrar ,
它创建了 MethodSecurityMetadataSourceAdvisor 切面, 并且指定了上面的拦截器名字作为构造参数, 使用 MethodSecurityMetadataSource 的实现(实现也有多种,通过组合的方式), 确定需要切入的bean(后面从方法中提取权限表达式,也是交给这个来实现)
所以后面的流程就是:
- 当一个请求来到切入的方法,就会被拦截器处理, MethodSecurityInterceptor 拦截器 会拿到 AOP里面的 MethodInvocation,
- 然后它会根据方法中的注解, 提取出所需权限, 交给访问决策管理器, 访问决策管理器 再交给 投票器,
- 因此, 上面创建的投票器 又会交给 advice, advice又交给handler处理, 也就是下面定义的这个handler处理,
- handler再利用el表达式计算, el会需要一个rootObject, 具体方法可以定义在rootObject里面, 只需要返回布尔值即可
package com.zzhua.blog.config.security.auth;import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;/*可参考:如何在 Spring Security 中自定义权限表达式-https://juejin.cn/post/7119086250610409508此handler 将会被注入到 GlobalMethodSecurityConfiguration#setMethodSecurityExpressionHandler 作为 handlerGlobalMethodSecurityConfiguration 定义了一个 PreInvocationAuthorizationAdvice 的bean, 获取并设置了上面定义的 handlerGlobalMethodSecurityConfiguration 并且定义了aop中的 methodSecurityInterceptor()拦截器,会去创建访问决策管理器访问决策管理器会去添加投票器(当然,不止这一种投票器),会创建一个 PreInvocationAuthorizationAdviceVoter, 里面会传入上面定义的Advice,@EnableWebSecurity引入了一个 MethodSecurityMetadataSourceAdvisorRegistrar ,它创建了 MethodSecurityMetadataSourceAdvisor 切面, 并且指定了上面的拦截器名字作为构造参数,使用 MethodSecurityMetadataSource 的实现(实现也有多种,通过组合的方式), 确定需要切入的bean(后面从方法中提取权限表达式,也是交给这个来实现)所以后面的流程就是:当一个请求来到切入的方法,就会被拦截器处理, MethodSecurityInterceptor 拦截器 会拿到 AOP里面的 MethodInvocation,然后它会根据方法中的注解, 提取出所需权限, 交给访问决策管理器, 访问决策管理器 再交给 投票器,因此, 上面创建的投票器 又会交给 advice, advice又交给handler处理, 也就是下面定义的这个handler处理,handler再利用el表达式计算, el会需要一个rootObject, 具体方法可以定义在rootObject里面, 只需要返回布尔值即可
*/
@Component
public class SysMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {@Overrideprotected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,MethodInvocation invocation) {// 换成自己的实现,其它的都照抄源码里面的(下面又多了可以很多自定义的东西了)SysMethodSecurityExpressionRoot root = new SysMethodSecurityExpressionRoot(authentication);root.setThis(invocation.getThis());root.setPermissionEvaluator(getPermissionEvaluator());root.setTrustResolver(new AuthenticationTrustResolverImpl());root.setRoleHierarchy(getRoleHierarchy());// root.setDefaultRolePrefix("ROLE_");return root;}}
SysMethodSecurityExpressionRoot
package com.zzhua.blog.config.security.auth;import com.zzhua.blog.config.constant.SysConstants;
import com.zzhua.blog.config.security.UserDetailDTO;
import com.zzhua.blog.util.SecurityUtil;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;class SysMethodSecurityExpressionRootextends SecurityExpressionRootimplements MethodSecurityExpressionOperations {private Object filterObject;private Object returnObject;private Object target;SysMethodSecurityExpressionRoot(Authentication a) {super(a);}/* 自定义鉴权方法 */public boolean isAuth(String permission) {UserDetailDTO userDetailDTO = SecurityUtil.getPrincipal();if (SysConstants.IS_ADMIN.equals(userDetailDTO.getIsAdmin())) {return true;} else {List<String> authories = getAuthories();for (String authory : authories) {if (Objects.equals(authory, permission)) {return true;}}}return false;}private List<String> getAuthories() {Collection<? extends GrantedAuthority> authorities = getAuthentication().getAuthorities();List<String> authoritys = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());return authoritys;}public void setFilterObject(Object filterObject) {this.filterObject = filterObject;}public Object getFilterObject() {return filterObject;}public void setReturnObject(Object returnObject) {this.returnObject = returnObject;}public Object getReturnObject() {return returnObject;}void setThis(Object target) {this.target = target;}public Object getThis() {return target;}
}相关文章:
Security方法注解权限控制过程及自定义权限表达式
文章目录 使用内置的权限表达式PreAuthorizePermissionEvaluator 自定义权限表达式SysMethodSecurityExpressionHandler源码流程 SysMethodSecurityExpressionRoot 使用内置的权限表达式 PreAuthorize 这个用来判断超级管理员的话,还得在表达式上加上或 Permissi…...
vue 省市县三级联动
1、 <template><div>所在省<el-select popper-class"eloption" :popper-append-to-body"true"change"getShiList(obj.province)" v-model"obj.province" placeholder"请选择所在省" clearableclear"re…...
ChatGPT实现编程语言转换
编程语言转换 对于程序员来说,往往有一类工作,是需要将一部分业务逻辑实现从服务端转移到客户端,或者从客户端转移到服务端。这类工作,通常需要将一种编程语言的代码转换成另一种编程语言的代码,这就需要承担这项工作…...
浅拷贝和深拷贝
浅拷贝: 定义:浅拷贝(Shallow Copy)是一种简单的对象复制方式,将一个对象的数据成员直接复制给另一个对象(通常是通过默认的复制构造函数或赋值运算符实现),这些数据成员可以是基本…...
进程地址空间与页表方面知识点(缺页中断及写时拷贝部分原理)
谢谢阅读,如有错误请大佬留言!! 目录 谢谢阅读,如有错误请大佬留言!! 抛出总结 开始介绍 发现问题 进程地址空间(虚拟地址) 页表 物理内存与进程地址空间映射 缺页中断基本…...
Photoshop如何使用滤镜之实例演示?
文章目录 0.引言1.将普通照片制作成油画效果2.使用液化滤镜修出完美身材3.用镜头光晕滤镜制作唯美的逆光人像4.用Camera Raw滤镜对偏色风景照进行调色 0.引言 因科研等多场景需要进行绘图处理,笔者对PS进行了学习,本文通过《Photoshop2021入门教程》及其…...
Flutter 组件抽取:日期(DatePicker)、时间(TimePicker)弹窗选择器【仿照】
简介 仿照《Flutter 仿ios自定义一个DatePicker》实行的日期弹窗选择器(DatePicker)、时间弹窗选择器(TimePicker) 效果 范例 class _TestPageState extends State<TestPage> {overridevoid initState() {super.initStat…...
基于opencv的YOLOV3对图片的目标检测
目录 1. 准备工作 2. utils 函数 2.1 plot_show 函数 2.2 get_prediction 函数 2.3 draw_bounding_box 绘制边界框函数...
Mermaid流程图
所有流程图都由节点,几何形状和边缘,箭头或线条组成。mermaid代码定义了这些节点和边缘的制作和交互方式。 它还可以容纳不同的箭头类型、多方向箭头以及与子图之间的链接。 1、流程图的方向 TB - 从上到下TD - 自上而下/与上到下相同BT - 从下到上RL -…...
国产!全志科技T507-H工业核心板( 4核ARM Cortex-A5)规格书
1核心板简介 创龙科技 SOM-TLT507 是一款基于全志科技 T507-H 处理器设计的 4 核 ARM Cortex-A 53 全国产工业核心板,主频高达 1.416GHz 。核心板 CPU 、ROM 、RAM、电源、晶振等所有元器件均采用国产工业级方案,国产化率 100%。 核心板通过邮票孔连接方式引出 MIPI CSI 、…...
java小记 2023-05-05
public class Test {/*** 谓类的方法就是指类中用static 修饰的方法(非static 为实例方法),比如main 方法,那么可以以main* 方法为例,可直接调用其他类方法,必须通过实例调用实例方法,this 关键…...
CentOS安装Nginx
准备工作 在安装Nginx之前,我们需要进行一些准备工作: 确认系统是否已经安装了Nginx。如果已经安装了,需要卸载掉旧版本。安装EPEL源,以获取Nginx的软件包。安装必要的依赖软件包。 卸载旧版Nginx 如果已经安装了旧版本的Ngin…...
CSS布局基础(CSS书写顺序 导航栏写法 常见问题)
CSS布局基础(CSS书写顺序 & 导航栏写法) CSS布局基础(CSS书写顺序)导航栏写法PC端网页开发一般步骤容易出问题的点 CSS布局基础(CSS书写顺序) 布局定位属性自身属性(宽高,边框&…...
打造卓越 QML 层级设计:从入门到精通
目录标题 引言:QML 层级设计的重要性1.1 什么是 QML1.2 层级设计的核心理念1.3 实际应用案例 QML 基础知识2.1 语言概述2.2 基本元素2.3 属性和信号 设计原则与规范3.1 命名规范3.1.1 标识符命名3.1.2 文件命名3.1.3 文件夹命名 3.2 代码风格3.2.1 缩进与空格3.2.2 …...
shell流程控制之条件判断练习
1、判断当前磁盘剩余空间是否有20G,如果小于20G,则将报警邮件发送给管理员,每天检查一次磁盘剩余空间。 因为如果磁盘剩余空间小于20G需要报警发送邮件给管理员,所以需要对管理员的邮箱进行设置 (1)首先…...
linux中TF启动卡制作:磁盘分区文件同步
文章目录 前言:1. 连接TF卡2. 磁盘卸载载与分区2.1 磁盘卸载2.2 创建第一个分区2.3 创建第二个分区 3. 磁盘格式化4. 文件同步5. 检查与BOOT分区启动文件拷贝总结: 前言: TF卡在linux环境下配置好相关软件后,把配置好的系统以及软…...
【操作系统OS】学习笔记:第一章 操作系统基础【哈工大李治军老师】
基于本人观看学习 哈工大李治军老师主讲的操作系统课程 所做的笔记,仅进行交流分享。 特此鸣谢李治军老师,操作系统的神作! 如果本篇笔记帮助到了你,还请点赞 关注 支持一下 ♡>𖥦<)!! 主页专栏有更多࿰…...
Linux C/C++ 网络编程中地址格式转换(inet_pton和inet_ntop函数)
网络编程中地址格式转换(inet_pton和inet_ntop函数) 地址格式转换 #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>int inet_pton(int af , const char * src ,void * dst);(1…...
庖丁解牛函数知识---C语言《2》
目录 前言: 1.嵌套调用函数 2.链式访问 3.函数的声明与定义 4.*递归 5.递归与非递归 ❤博主CSDN:啊苏要学习 ▶专栏分类:C语言◀ C语言的学习,是为我们今后学习其它语言打好基础,C生万物! 开始我们的C语言之旅吧…...
Git 使用教程:最详细、最正宗手把手教学(万字长文)
目录 一:Git二:SVN与Git的的区别三、安装Git四:常规操作五:远程仓库六:创建与合并分支七:bug分支八:多人协作九:git可视化工具 Git Git 是一种分布式版本控制系统,用于…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
