IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot 使用Shiro自定义权限拦截器实现多个perm权限的配置 -> 正文阅读

[Java知识库]SpringBoot 使用Shiro自定义权限拦截器实现多个perm权限的配置

本文结合了两位大佬的文章,自己实现了多个perm权限的配置
主要参考:SpringBoot-Shiro自定义过滤器实现配置多个权限
辅助参考:SpringBoot 使用Shiro权限框架自定义拦截器检查token失效

一.为什么要自定义过滤器

在项目开发过程中,安全对于后台管理很重要。shiro是一个比较常流行的安全框架,在项目中的权限配置会有各种不同的需求,例如有的url需要用户拥有多个权限中的一个权限就能够访问,这个就要自己编写拦截器(过滤器)的规则。

二.Shiro中的权限控制

shiro权限控制是在用户登录时会再realm中增加该用户的权限信息,在登录的时候会根据请求的url和相关的权限做映射。在用户请求具体url时,会根据url获得对应的权限,在到拦截器中做权限的校验。

我们看一下原本的两种写法。

//user:add 和 root  权限都拥有时才可以访问
fiterMap.put("/user/*","perms[user:add,root]");
//有 root 权限就可以访问
fiterMap.put("/user/*","perms[root]");

上面的权限校验规则是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();
			//遍历多个权限 以","分割权限 每个权限都满足才返回 true
            while(var3.hasNext()) {
                Permission p = (Permission)var3.next();
                if (!this.isPermitted(p, info)) {
                    return false;
                }
            }
        }
        return true;
    }

三.解决问题–实现拥有多个权限中的一个权限就能够访问

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

自定义Shiro过滤器

RoleOrFilter.java
package com.company.gas.config;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;



public class RoleOrFilter extends AuthorizationFilter {


    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        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;
    }

}

** 2.ShiroConfig中shiroFilterFactoryBean方法中添加自定义过滤器**

//ShiroFilterFactoryBean
    @Bean(name = "bean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);//设置安全管理器

        RoleOrFilter roleOrFilter = new RoleOrFilter(); //自定义拦截器
        Map<String, Filter> myFilterMap = new HashMap<>();

        myFilterMap.put("e-perms",roleOrFilter);//可以配置RoleOrFilter的Bean
        //添加Shiro内置过滤器
        /**
         *  Shiro内置过滤器,可以实现权限相关的拦截器
         *  注意!!! 有顺序要求
         *      常见的过滤器:
         *          anon: 无需认证(登录)就可以访问
         *          authc: 必须登录认证才可以访问
         *          user: 如果使用remember功能可以直接访问
         *          perms: 该资源必须获得资源权限才可以访问
         *          roles: 该资源必须获得角色权限才可以访问
         */
        //设置自定义filter---
        //这里很重要:在springboot中 如何使用自定义的拦截器

        Map<String,String> filterMap = new LinkedHashMap<String, String>();
        filterMap.put("/myIndex","anon");
        filterMap.put("/myLogin","anon");//为了实现登录(数据写入)的请求,应将myLogin也放行
        filterMap.put("/druid/**","anon");//取消拦截druid数据源监控页面
        filterMap.put("/facility/add","e-perms[2|3]");//资源授权拦截,对应成功则可进入
        filterMap.put("/**","authc");  //实现拦截功能

        //设置未授权提示页面
        bean.setUnauthorizedUrl("/myWeishouquan");
        //设置登录错误提示页面
        bean.setLoginUrl("/toLogin");

        bean.setFilterChainDefinitionMap(filterMap);
        //使用自定义拦截器
        bean.setFilters(myFilterMap);
        return bean;
    }


我们达到的效果:

  • 保持“,”表示多个权限的并列关系,每个“,”分割的字符串可能是多个“或”权限的集合,再用“|”分割字符串,“|”需要转义。

修改后的权限控制:

    fiterMap.put("/user/add","e-perms[user:add|root]");
    fiterMap.put("/user/update","e-perms[user:update|root]");

结果 使得拥有user:add或者root权限的用户都能成功的访问 /user/add 接口了,同时兼容了shiro自带的权限检验规则

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:22:10  更:2021-08-01 14:23:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 12:50:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码