使用自定义注解和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    自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * 类名 :权限控制注解
 * 用法 :
 * 创建人 : shyroke
 * 时间:2018/12/18 10:33
 */
 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionAnnotation {
 
    String permissionName();
 
}

    

    3.2    编写切面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
 * 类名 :权限的切面类
 * 用法 :
 * 创建人 : 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * 类名 :用户的工具类
 * 用法 :
 * 创建人 : 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    使用

1
2
3
4
5
6
@PermissionAnnotation(permissionName = "boke:*")
@PostMapping(value = "desc")
@ResponseBody
public R desc(){
    return R.ok("删除成功!");
}

 

    3.4    结果

image.png

posted @   shyroke、  阅读(3170)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2017-12-18 (二)Centos之在VM虚拟机中安装Centos操作系统
2017-12-18 (一)Centos之VMware虚拟机安装
作者:shyroke 博客地址:http://www.cnblogs.com/shyroke/ 转载注明来源~
点击右上角即可分享
微信分享提示