使用自定义注解和AOP管理shiro权限
一、场景
在使用shiro框架的时候,遇到了这样的需求:本系统有多个用户,每个用户分配不同角色,每个角色的权限也不一致。比如A用户拥有新闻列表的增删改查权限,而B用户只有查看新闻列表的权限,而没有删除、新增、修改的权限,此时有3种方案:1、不给B用户分配删除、新增、修改的菜单,这样用户就无法点击从而无法操作。2、给B用户分配菜单,后台中进行增删改查操作时都要进行权限验证。 3、给B用户分配菜单并且进行操作的时候校验权限。
显然,第2、3种方案比第1中方案要安全。本系统中使用第二种方案。
二、为什么使用注解+AOP
使用shiro过程中一般都会自定义Realm,Realm主要进行权限和登录的校验,当校验登录用户是否有某个权限的时候,有2种方式:1、使用注解 @RequiresPermissions("news:*") 来判断用户是否有news的所有权限。 2、使用Subject.isPermitted("news:*") 方法判断用户是否有news的所有权限。
这两种方法的区别在于,第一种:比如当前用户在新闻列表中删除某篇新闻,但是该用户并没有这种权限,此时会抛出异常,我们需要处理异常即可,但是页面进行跳转,我们希望用户在新闻列进行删除操作的时候,如果没有该权限则会弹窗提示,而不是跳转到统一的异常页面。 第二种,可以实现第一种的不足,但是没有第一种方便快捷。
为了综合上述两种的有点以及缺点,实现shiro校验权限时有异常但不刷新页面,同时以注解的形式使用。
三、实现
实现的效果:需要校验权限的方法比如删除方法del(),只要在该方法上添加自定义注解,即可实现上述效果。
3.1 自定义注解
/**
* 类名 :权限控制注解
* 用法 :
* 创建人 : shyroke
* 时间:2018/12/18 10:33
*/ @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionAnnotation { String permissionName(); }
3.2 编写切面
/**
* 类名 :权限的切面类
* 用法 :
* 创建人 : shyroke
* 时间:2018/12/18 10:38
*/
@Aspect
@Component
public class PermissionAspect { @Pointcut("@annotation(com.shyroke.daydayzhuan.util.PermissionAnnotation)")
private void permisson(){ } /**
* 给添加PermissionAnnotation注解的方法校验权限,而不必每个方法内都判断权限
* @param joinPoint
* @param permissionAnnotation
* @return
* @throws Throwable
*/
@Around("permisson()&&@annotation(permissionAnnotation)")
public Object advice(ProceedingJoinPoint joinPoint, PermissionAnnotation permissionAnnotation) throws Throwable { R r = null; r = (R) joinPoint.proceed(); String permissionName =permissionAnnotation.permissionName(); if(StringUtils.isEmpty(permissionName)){
r.setFlag(false);
r.setMessage("权限名称不能为空");
return r;
} //校验当前登录用户是否有该权限
boolean isPermission = UserUtils.isPermission(permissionName); if(!isPermission){
r.setFlag(false);
r.setMessage("没有此操作权限!");
} return r; } }
UserUtils.java
/**
* 类名 :用户的工具类
* 用法 :
* 创建人 : shyroke
* 时间:2018/12/18 14:39
*/
public class UserUtils { /**
* 校验当前登录用户是否有该权限
* @param permissionname 权限名称
* @return
*/
public static boolean isPermission(String permissionname) { Subject subject = SecurityUtils.getSubject(); if(subject.isPermitted(permissionname)){
return true;
}else{
return false;
} }
}
3.3 使用
@PermissionAnnotation(permissionName = "boke:*")
@PostMapping(value = "desc")
@ResponseBody
public R desc(){
return R.ok("删除成功!");
}
3.4 结果
使用自定义注解和AOP管理shiro权限的更多相关文章
- 通过AOP自定义注解实现日志管理
前言: 通过自定义注解和AOP结合的方式,实现日志的记录功能 大致流程:项目运行->用户操作调用业务处理类->通过自定义的注解(我理解为一个切点)->进入到AOP切面类(在这里可以获 ...
- 如何通过自定义注解实现AOP切点定义
面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...
- SpringBoot自定义注解、AOP打印日志
前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...
- 基于springboot通过自定义注解和AOP实现权限验证
一.移入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...
- spring AOP自定义注解 实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- 手写SpringBoot自动配置及自定义注解搭配Aop,实现升级版@Value()功能
背景 项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos. 我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中.项目中使 ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- java/springboot自定义注解实现AOP
java注解 即是注释了,百度解释:也叫元数据.一种代码级别的说明. 个人理解:就是内容可以被代码理解的注释,一般是一个类. 元数据 也叫元注解,是放在被定义的一个注解类的前面 ,是对注解一种限制. ...
- Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...
随机推荐
- BigDecimal加减乘除计算
一.简述 java.math.BigDecimal不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值(unscaledValue)和32位的整数标度(scale)组成. ...
- 使用python处理selenium中的获取元素属性
# 获取我的订单元素class属性值 get_class_name = driver.find_element_by_link_text('我的订单').get_attribute('class') ...
- JUnit 4.x 与 5.x 的区别?
区别项 4.x 5.x 手动把测试和测试方法声明为public 需要 不需要 @Test 与JUnit 4的@Test注解不同的是,它没有声明任何属性,因为JUnit Jupiter中的测试扩展是基于 ...
- MySQL中Count函数的参数该传入什么样的值?
MySQL中Count函数的参数该传入什么样的值? 查询用户表中总记录 用户表中信息如下: 1.SELECT COUNT(*) FROM USER 结果为:3条 2. SELECT COUNT(us ...
- IE浏览器兼容性问题输出
1.时间函数 var startTime=new Date(a); var endTime=new Date(b); 如果a,b的时间格式是:“2017-08-01,需要将格式转换成“2017/08/ ...
- HDFS的读写流程
1.2. 客户端向NameNode发起创建文件的请求,在NameNode上创建一个文件名,并且返回一个输出流 3.客户端向输出流发起写入数据的请求 4.输出流向NameNode请求写数据,NameNo ...
- Elasticsearch(一)基础入门
介绍 Elasticsearch 是一个实时的分布式搜索分析引擎, 它能让你以前所未有的速度和规模,去探索你的数据. 它被用作全文检索.结构化搜索.分析以及这三个功能的组合: Elasticsearc ...
- What is react-native link?
What is react-native link? or Should you just use react-native link when linking any dependency or s ...
- linux学习11 Linux基础命令及命令历史
一.Linux系统上的文件类型 1.- :常规文件:在其它程序中用f表示.比如我们用ls -l命令查看的第一个内容 [root@localhost ~]# ls -l total -rw------- ...
- 【CSGRound2】逐梦者的初心(洛谷11月月赛 II & CSG Round 2 T3)
题目描述# 给你一个长度为\(n\)的字符串\(S\). 有\(m\)个操作,保证\(m≤n\). 你还有一个字符串\(T\),刚开始为空. 共有两种操作. 第一种操作: 在字符串\(T\)的末尾加上 ...