shiro 自定义拦截器配置多个权限实现

一、问题产生

在项目开发过程中,安全对于后台管理很重要。shiro是一个比较常流行的安全框架,网上关于shiro的使用和实现原理也比较全面。这里不做详细介绍,在项目中的权限配置会有各种不同的需求,例如有的url需要用户拥有多个权限中的一个权限就能够访问,这个就要自己编写拦截器的规则。

二、具体场景

自定义的拦截器没有重写PermissionsAuthorizationFilter的isAccessAllowed方法,使用的权限控制的默认的拦截器。yml文件的全蝎配置如下:

   - /user/getStatis-->e-perms[green,user]
   - /user/findUserByNameAndTime-->e-perms[air,user,wallet]
   - /greenplant/findTreesType-->e-perms[seeds,plants]
   - /wallet/findWalletByCondition-->e-perms[user,wallet]

例如:/user/getStatis的业务需求是拥有green或者user权限的用户都要有权限能调用该接口。但是上面的配置导致无论是拥有green或者user权限的用户都不能访问该接口。

三、原因分析

shiro权限控制是在用户登录时会再realm中增加该用户的权限信息,在登录的时候会根据请求的url和相关的权限做映射。在用户请求具体url时,会根据url获得对应的权限,在到拦截器中做权限的校验。上面配置不生效的原因是因为shiro的下面代码,该代码是在PermissionsAuthorizationFilter中,默认的权限校验规则。

public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        Subject subject = this.getSubject(request, response);
        String[] perms = (String[])((String[])mappedValue);
        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!subject.isPermitted(perms[0])) {
                    isPermitted = false;
                }
            } else if (!subject.isPermittedAll(perms)) {
                isPermitted = false;
            }
        }

        return isPermitted;
    }

从上面的代码可以看出,我们的配置会默认被抢转为string类型的字符串数组。当只有一个权限时,会直接判断有没有该权限;当配置多个权限时,从下面的代码可以看出只用在请求url的用户拥有所有的权限时,才会返回true,否则就会被拒绝访问。

protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
        if (permissions != null && !permissions.isEmpty()) {
            Iterator var3 = permissions.iterator();

            while(var3.hasNext()) {
                Permission p = (Permission)var3.next();
                if (!this.isPermitted(p, info)) {
                    return false;
                }
            }
        }

        return true;
    }

四、问题解决

shiro源码只考虑了权限的和的问题没有通过配置解决权限的或的问题。因此为了满足业务需求,在自定义拦截器中需要重写PermissionsAuthorizationFilter的isAccessAllowed方法。为了满足“和”和“或”的不同权限配置的需求,对isAccessAllowed方法做如下修改:

@Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        Subject subject = this.getSubject(request, response);
        String[] perms = (String[]) ((String[]) mappedValue);
        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!isOneOfPermitted(perms[0], subject)) {
                    isPermitted = false;
                }
            } else if (!isAllPermitted(perms,subject)) {
                isPermitted = false;
            }
        }
        return isPermitted;
    }

    /**
     * 以“,”分割的权限为并列关系的权限控制,分别对每个权限字符串进行“|”分割解析
     * 若并列关系的权限有一个不满足则返回false
     *
     * @param permStrArray 以","分割的权限集合
     * @param subject      当前用户的登录信息
     * @return 是否拥有该权限
     */
    private boolean isAllPermitted(String[] permStrArray, Subject subject) {
        boolean isPermitted = true;
        for (int index = 0, len = permStrArray.length; index < len; index++) {
            if (!isOneOfPermitted(permStrArray[index], subject)) {
                isPermitted = false;
            }
        }
        return isPermitted;
    }

    /**
     * 判断以“|”分割的权限有一个满足的就返回true,表示权限的或者关系
     *
     * @param permStr 权限数组种中的一个字符串
     * @param subject 当前用户信息
     * @return 是否有权限
     */
    private boolean isOneOfPermitted(String permStr, Subject subject) {
        boolean isPermitted = false;
        String[] permArr = permStr.split("\\|");
        if (permArr.length > 0) {
            for (int index = 0, len = permArr.length; index < len; index++) {
                if (subject.isPermitted(permArr[index])) {
                    isPermitted = true;
                }
            }
        }
        return isPermitted;
    }

方法做了上述修改,保持“,”表示多个权限的并列关系,每个“,”分割的字符串可能是多个“或”权限的集合,再用“|”分割字符串,“|”需要转义。修改代码后,权限配置做了如下修改:

   - /user/getStatis-->e-perms[green|user]
   - /user/findUserByNameAndTime-->e-perms[air|user|wallet]
   - /greenplant/findTreesType-->e-perms[seeds|plants]
   - /wallet/findWalletByCondition-->e-perms[user|wallet]

这样就能是使得拥有green或者user权限的用户都能成功的访问 /user/getStatis接口了,同时兼容了shiro自带的权限检验规则。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值