RuoYi-Vue-Plus (SaToken 注解鉴权)

一、SaInterceptor  注解鉴权和路由拦截鉴权

拦截器:SaInterceptor

实现类位置: cn.dev33.satoken.interceptor.SaInterceptor

功能:Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力

/*** 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 * @param auth 认证函数,每次请求执行 */
public SaInterceptor(SaParamFunction<Object> auth) {this.auth = auth;
}

SaInterceptor 有参构造的参数,SaParamFunction: 

单形参、无返回值的函数式接口,方便开发者进行 lambda 表达式风格调用,如下@FunctionalInterface 标注
@FunctionalInterface
public interface SaParamFunction<T> {/*** 执行的方法 * @param r 传入的参数 */void run(T r);}

/*** Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力 * * @author click33* @since 1.31.0*/
public class SaInterceptor implements HandlerInterceptor {/*** 是否打开注解鉴权,配置为 true 时注解鉴权才会生效,配置为 false 时,即使写了注解也不会进行鉴权*/public boolean isAnnotation = true;/*** 认证函数:每次请求执行 * <p> 参数:路由处理函数指针 */public SaParamFunction<Object> auth = handler -> {};/*** 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 */public SaInterceptor() {}/*** 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 * @param auth 认证函数,每次请求执行 */public SaInterceptor(SaParamFunction<Object> auth) {this.auth = auth;}/*** 设置是否打开注解鉴权:配置为 true 时注解鉴权才会生效,配置为 false 时,即使写了注解也不会进行鉴权* @param isAnnotation /* @return 对象自身*/public SaInterceptor isAnnotation(boolean isAnnotation) {this.isAnnotation = isAnnotation;return this;}/*** 写入 [ 认证函数 ]: 每次请求执行* @param auth / * @return 对象自身 */public SaInterceptor setAuth(SaParamFunction<Object> auth) {this.auth = auth;return this;}// ----------------- 验证方法 ----------------- /*** 每次请求之前触发的方法 */@Override@SuppressWarnings("all")public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {try {// 这里必须确保 handler 是 HandlerMethod 类型时,才能进行注解鉴权if(isAnnotation && handler instanceof HandlerMethod) {// 获取此请求对应的 Method 处理函数 Method method = ((HandlerMethod) handler).getMethod();// 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权if(SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) {// 注意这里直接就退出整个鉴权了,最底部的 auth.run() 路由拦截鉴权也被跳出了return true;}// 执行注解鉴权SaStrategy.instance.checkMethodAnnotation.accept(method);}// Auth 路由拦截鉴权校验auth.run(handler);} catch (StopMatchException e) {// StopMatchException 异常代表:停止匹配,进入Controller} catch (BackResultException e) {// BackResultException 异常代表:停止匹配,向前端输出结果// 		请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 back 前自行设置 Content-Type 为 application/json// 		例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");if(response.getContentType() == null) {response.setContentType("text/plain; charset=utf-8"); }response.getWriter().print(e.getMessage());return false;}// 通过验证 return true;}}

一、@SaIgnore 

忽略认证:表示被修饰的方法或类无需进行注解认证和路由拦截认证
请注意:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。

拦截器前置处理逻辑:(对上面SaInterceptor  拦截器解读)

  1. 1- preHandle 前置方法中对SaIgnore注解进行了判断,如果标注就忽略鉴权。
// 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权
if(SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) {// 注意这里直接就退出整个鉴权了,最底部的 auth.run() 路由拦截鉴权也被跳出了return true;
}
  1. 2-  执行注解鉴权,校验其他注解,
// 拦截器执行注解鉴权代码,主要是调用策略类SaStrategy (是Sa-Token 策略对象,checkMethodAnnotation 方法
SaStrategy.instance.checkMethodAnnotation.accept(method);

checkMethodAnnotation: 

	/*** 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)*/public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {// 先校验 Method 所属 Class 上的注解instance.checkElementAnnotation.accept(method.getDeclaringClass());// 再校验 Method 上的注解instance.checkElementAnnotation.accept(method);};

 checkElementAnnotation:

·	/*** 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)*/public SaCheckElementAnnotationFunction checkElementAnnotation = (element) -> {// 校验 @SaCheckLogin 注解SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.instance.getAnnotation.apply(element, SaCheckLogin.class);if(checkLogin != null) {SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);}// 校验 @SaCheckRole 注解。。。。。省略其他

3- 执行SoToken拦截器

Auth 路由拦截鉴权校验: auth.run(handler);实际执行是:SaTokenConfig 配置类中的 handler 处理,即如下
  public void addInterceptors(InterceptorRegistry registry) {// 注册路由拦截器,自定义验证规则registry.addInterceptor(new SaInterceptor(new SaParamFunction<Object>() {@Overridepublic void run(Object handler) {AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);// 登录验证 -- 排除多个路径SaRouter// 获取所有的.match(allUrlHandler.getUrls())// 对未排除的路径进行检查.check(() -> {// 检查是否登录 是否有tokenStpUtil.checkLogin();});}})).addPathPatterns("/**")// 排除不需要拦截的路径.excludePathPatterns(securityProperties.getExcludes());}

 拦截器的实现类:

二、@SaCheckLogin

上面 preHandle 方法中,

	// 执行注解鉴权SaStrategy.instance.checkMethodAnnotation.accept(method);

点击进去 checkMethodAnnotation:

	/*** 对一个 [Method] 对象进行注解校验 (注解鉴权内部实现)*/public SaCheckMethodAnnotationFunction checkMethodAnnotation = (method) -> {// 先校验 Method 所属 Class 上的注解instance.checkElementAnnotation.accept(method.getDeclaringClass());// 再校验 Method 上的注解instance.checkElementAnnotation.accept(method);};

调用 checkElementAnnotation  进行 SaCheckLogin注解的校验:

1-先从元素上获取注解

2- SaManager.getStpLogic(checkLogin.type(), false) 获取到StpLogic,进行 SaCheckLogin 注解的登录鉴权

Sa-Token :权限认证,逻辑实现类(所有SoToken注解认证都在这边实现)

	/*** 对一个 [元素] 对象进行注解校验 (注解鉴权内部实现)*/public SaCheckElementAnnotationFunction checkElementAnnotation = (element) -> {// 校验 @SaCheckLogin 注解SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.instance.getAnnotation.apply(element, SaCheckLogin.class);if(checkLogin != null) {SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);}
。。。。。省略下文

三、@SaCheckRole  @SaCheckPermission

功能:

  • SaCheckRole  :校验角色注解
  • SaCheckPermission :权限校验注解

下面用 SaCheckRole  来进行解读:

策略类中 SaManager.getStpLogic(checkLogin.type(), false) 返回 StpLogic 对象

调用了checkByAnnotation 方法,进行匹配角色:如下

SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);
	/*** 根据注解 ( @SaCheckRole ) 鉴权** @param at 注解对象 */public void checkByAnnotation(SaCheckRole at) {String[] roleArray = at.value();//1-满足所有角色才能校验通过if(at.mode() == SaMode.AND) {this.checkRoleAnd(roleArray);	} else {//2- 满足任意一个角色就能通过this.checkRoleOr(roleArray);	}}

在 上面代码 checkRoleAnd  和  checkRoleOr 中都调用了 

getRoleList 方法,该方法是用于查询角色权限

其查询权限的接口有2个实现类

其中 SaPermissionImpl 实现类,是我这在SaToken配置类中配置

/*** 权限接口实现(使用bean注入方便用户替换)*/@Beanpublic StpInterface stpInterface() {return new SaPermissionImpl();}

 实现了:

菜单权限查询方法getPermissionList

角色权限查询方法getRoleList

public class SaPermissionImpl implements StpInterface {/*** 获取菜单权限列表*/@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {LoginUser loginUser = LoginHelper.getLoginUser();UserType userType = UserType.getUserType(loginUser.getUserType());if (userType == UserType.SYS_USER) {return new ArrayList<>(loginUser.getMenuPermission());} else if (userType == UserType.APP_USER) {// 其他端 自行根据业务编写}return new ArrayList<>();}/*** 获取角色权限列表*/@Overridepublic List<String> getRoleList(Object loginId, String loginType) {LoginUser loginUser = LoginHelper.getLoginUser();UserType userType = UserType.getUserType(loginUser.getUserType());if (userType == UserType.SYS_USER) {return new ArrayList<>(loginUser.getRolePermission());} else if (userType == UserType.APP_USER) {// 其他端 自行根据业务编写}return new ArrayList<>();}
}

四、@SaCheckSafe

作用:二级认证(基于redis实现)

使用场景:

比如代码托管平台的仓库删除操作,尽管我们已经登录了账号,当我们点击 [删除] 按钮时,还是需要再次输入一遍密码,这么做主要为了两点:

  1. 保证操作者是当前账号本人。
  2. 增加操作步骤,防止误删除重要数据。

 SaToken 关于二级认证的文档如下:(很详细)二级认证 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html#/up/safe-auth

 简单使用方法:

  • 先调用StpUtil.openSafe("add", 600),在redis 缓存中保存数据
  • 之后在方法上面标注@RequestMapping("add") 注解即可开启

其代码实现逻辑如下注释:

	/*** 1-校验:检查当前会话是否已通过指定业务的二级认证,如未通过则抛出异常** @param service 业务标识  */public void checkSafe(String service) {//获取tokenString tokenValue = getTokenValue();//判断token是否有效,否则抛出异常if ( ! isSafe(tokenValue, service)) {throw new NotSafeException(loginType, tokenValue, service).setCode(SaErrorCode.CODE_11071);}}/*** 2-判断:指定 token 是否处于二级认证时间内** @param tokenValue Token 值  * @param service 业务标识  * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时 */public boolean isSafe(String tokenValue, String service) {// 1、如果提供的 Token 为空,则直接视为未认证if(SaFoxUtil.isEmpty(tokenValue)) {return false;}// 2、如果缓存中可以查询出指定的键值,则代表已认证,否则视为未认证//splicingKeySafe(tokenValue, service) 返回如下:// 格式:<Token名称>:<账号类型>:<safe>:<业务标识>:<Token值>// 形如:satoken:login:safe:important:gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__String value = getSaTokenDao().get(splicingKeySafe(tokenValue, service));return !(SaFoxUtil.isEmpty(value));}

 五、@SaCheckSafe

功能: 账号封禁(基于redis实现)

场景:

  1.         账号封禁
  2.         分类封禁 (封禁部分功能)
  3.         阶梯封禁 (比如按照时间长短封禁、按照等级 1234封禁)
  4.         使用注解封禁,如下:
// 校验当前账号是否被封禁 comment 服务,如果已被封禁会抛出异常,无法进入方法 
@SaCheckDisable("comment")// 校验当前账号是否被封禁 comment、place-order、open-shop 等服务,指定多个值,只要有一个已被封禁,就无法进入方法 
@SaCheckDisable({"comment", "place-order", "open-shop"})// 阶梯封禁,校验当前账号封禁等级是否达到5级,如果达到则抛出异常 
@SaCheckDisable(level = 5)// 分类封禁 + 阶梯封禁 校验:校验当前账号的 comment 服务,封禁等级是否达到5级,如果达到则抛出异常 
@SaCheckDisable(value = "comment", level = 5)

API:账号封禁 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html#/up/disable

代码逻辑:

	/*** 校验:指定账号的指定服务,是否已被封禁到指定等级(如果已经达到,则抛出异常)* * @param loginId 指定账号id * @param service 指定封禁服务 * @param level 封禁等级 (只有 封禁等级 ≥ 此值 才会抛出异常)*/public void checkDisableLevel(Object loginId, String service, int level) {// 1、先前置检查一下这个账号是否被封禁了String value = getSaTokenDao().get(splicingKeyDisable(loginId, service));if(SaFoxUtil.isEmpty(value)) {return;}// 2、再判断被封禁的等级是否达到了指定级别Integer disableLevel = SaFoxUtil.getValueByType(value, int.class);if(disableLevel >= level) {throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service)).setCode(SaErrorCode.CODE_11061);}}

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

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

相关文章

重学java 19.面向对象 继承 上

走不出的那段阴霾&#xff0c;很多时候只不过是&#xff0c;我们把它当成了唯一 —— 24.4.22 面向对象整体知识导向&#xff1a; 知识梳理&#xff1a; 1.知道继承的好处 2.会使用继承 3.继承之后成员变量和成员方法的访问特点 4.方法的重写&#xff0c;知道方法重写的使用场景…

从构成看自来水厂自动化控制系统的创新与发展

自来水厂自动化控制系统涵盖了多个关键组成部分&#xff0c;包括水管理云平台、供水监控系统以及供水调度平台。 系统内嵌了一系列自主创新的核心算法&#xff0c;这些算法结合了数学建模、机器仿真和流体力学等多元数据模型&#xff0c;以优化设备间的关联和控制关系&#xf…

python爬虫 - 爬取html中的script数据(爬取新闻 36kr.com)

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;爬取新闻3. 使用re.search 方法&#xff0c;爬取新闻 1. 分析页面内容数据格式 打开 https://36kr.com/ 按F12&#xff08;或 在网页上右键 --> 检查&#xff08;Inspect&#xff09;&#xff09; 找…

大珩PPT助手一键颜色设置

大珩PPT助手最新推出的一键设置文字颜色和背景色功能&#xff0c;为用户在创建演示文稿时带来了更便捷、高效的体验。这一功能使用户能够轻松调整演示文稿中文字的颜色和幻灯片的背景色&#xff0c;以满足不同场合和主题的需要。 以下是该功能的几个关键特点和优势&#xff1a…

2024深圳杯东三省数学建模竞赛A题个火箭残骸的准确定位代码成品论文

问题重述 绝大多数火箭为多级火箭&#xff0c;下面级火箭或助推器完成既定任务后&#xff0c;通过级间分离装置分离后坠落。在坠落至地面过程中&#xff0c;残骸会产生跨音速音爆。为了快速回收火箭残骸&#xff0c;在残骸理论落区内布置多台震动波监测设备&#xff0c;以接收不…

账号安全基本措施2

sudo命令 sudo(superuser do)&#xff0c;允许系统管理员让普通用户执行一些或者全部的root命令的一个工具。 其配置在/etc/sudoers权。它允许系统管理员集中的管理用户的使用权限和使用的主机。属性必须为0440。 语法检查&#xff1a; 检查语法&#xff1a; 修改文件时&…

刷课必备!用Python实现网上自动做题

前言 开学少不了老师会布置一些 软件上面的作业&#xff0c;今天教大家用python制作自动答题脚本&#xff0c;100%准确率哦喜欢的同学记得关注、收藏哦 环境使用 Python3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —>…

【Qt 学习笔记】Qt常用控件 | 显示类控件 | Calendar Widget的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 显示类控件 | Calendar Widget的使用及说明 文章编号&am…

基于STM32实现流水灯【Proteus仿真】

详情更多 wechat&#xff1a;嵌入式工程师成长日记 https://mp.weixin.qq.com/s?__bizMzg4Mzc3NDUxOQ&mid2247485624&idx1&sn4e553234c2624777409bd2067a07aad8&chksmcf430de0f83484f6189b119d9d83ea6e6f2a85d13afaa04d218483918231c38e6382d3007061&tok…

「React Native」为什么要选择 React Native 作为的跨端方案

文章目录 前言一、常见因素二、举个栗子2.1 项目背景2.2 为什么选择 React Native2.3 项目实施2.4 成果总结 前言 没有完美的跨端技术&#xff0c;只有适合的场景。脱离适用场景去谈跨端技术没有什么意义。 一、常见因素 共享代码库&#xff1a; React Native 允许开发者编写…

第⑮讲:Ceph集群管理与监控操作指南

文章目录 1.查看集群的状态信息2.动态的查看集群的状态信息3.查看集群的利用率4.查看OSD的资源利用率5.查看OSD的列表6.查看各组件的状态7.查看集群的仲裁信息8.查看/修改集群组件sock的配置参数 1.查看集群的状态信息 通过集群状态信息可以看到集群的健康状态、各个组件的运行…

PMP新版考试也要复习49个过程?如何复习更高效?

PMP中有五大过程组、十大知识领域&#xff0c;共计49个子过程&#xff0c;那么如何才能快速的记住这49个子过程&#xff0c;可以参考这篇文章理解加深记忆。 记忆需要花费时间&#xff1a;30分钟 记忆持续时间&#xff1a;永久 接下来按照思路进行 场景&#xff1a;大家都熟…

粮油包装生产线的未来趋势:智能、环保与可持续发展

在当今世界&#xff0c;科技进步日新月异&#xff0c;智能化、环保和可持续发展已成为各行各业关注的焦点。粮油包装生产线作为食品产业链的重要环节&#xff0c;其未来发展趋势同样离不开这三大主题。星派将探讨粮油包装生产线的未来趋势&#xff0c;并展望其在智能、环保与可…

详解俄罗斯社媒平台VK广告推广如何开户?VK代理开户、费用、代运营流程

俄罗斯的VK&#xff08;VKontakte&#xff09;是当地常用的社交媒体平台&#xff0c;对于想要在俄罗斯市场推广产品的企业来说&#xff0c;VK广告投放是一个有效的渠道。以下是关于如何在VK上进行广告推广的开户流程、费用和代运营流程的详解&#xff1a; VK广告推广开户流程 …

海康Visionmaster-常见问题排查方法-启动阶段

VM试用版启动时&#xff0c;弹窗报错&#xff1a;加密狗未安装或检测异常&#xff1b;  问题原因&#xff1a;安装VM 的时候未选择软加密&#xff0c;选择了加密狗驱动&#xff0c;此时要使用软授权就出现了此现象。  解决方法&#xff1a; ① 首先确认软加密驱动正确安装…

机器学习入门:玩转sklearn库,AI写作

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

达芬奇调色:色彩理论入门

写在前面 整理一些达芬奇调色的笔记博文内容涉及&#xff1a; 一级调色是什么&#xff0c;以及 调色素材格式 log&#xff0c;raw&#xff0c;rec709 简单认知理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#…

基于SpringBoot+Vue的企业资产管理系统设计与实现

1、系统演示视频&#xff08;演示视频&#xff09; 2、需要请联系

hexo配置教程、主题使用及涉及的技术学习

一、背景 最近,一直想做一个属于自己的网站.可以从零开始搭建一个网站,顺便可以把日常中学到的技术用于实战,还可以顺便记录自己的所思所感,记录成长的过程. 方案 一开始的方案是从零开始,模仿常见个人博客的设计,基于vueSpringbootMySQL的去实现网站. 新建项目之后,发现vu…

C/C++ 入门(7)string类(STL)

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 请多多指教&#xff01; 目录 一、标准库中的string 1、了解 2、string类常用接口说明 1、常见的构造函数 2、容量操作 ​编辑 3、访问及遍历操作 4、修改操作 5、非成员函数 二、string类实现 …