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

    image.png

  • 相关阅读:
    [bzoj3224] 普通平衡树
    [总结] 三种常见的区间贪心问题
    [NOIP2014] 飞扬的小鸟
    POJ 1185 炮兵阵地
    WOJ 1538 Stones II 转化背包问题
    WOJ 1542 Countries 并查集转化新点+最短路
    UVA 11375 高精度Bign类
    2014_csu选拔1_B
    Codeforces 405D 数学问题
    Codeforces 400C 矩阵乘法 数学规律
  • 原文地址:https://www.cnblogs.com/shyroke/p/10138773.html
Copyright © 2020-2023  润新知