`
世道变了
  • 浏览: 1735 次
社区版块
存档分类
最新评论

简单扩展shiro 实现NOT、AND、OR权限验证(支持复杂一点的表达式)

阅读更多

简单扩展Shiro实现  类似
organization:create OR organization:update OR organization:delete

 ( organization:create Or organization:update ) OR  NOT organization:delete

 ( organization:create && organization:update ) OR  ! organization:delete

 

其中操作符不限大小写,支持and、or、not,以及&&、||、!

唯一缺点就是为了解析方便,所有内容必须用空格隔开


我先是看到了这篇博客:http://jinnianshilongnian.iteye.com/blog/1864800

然后觉得可以实现的更完善一些,突然想到可以用逆波兰表达式实现复杂一些的表达式解析

于是便有了这篇文章

实现思路:

1.将字符串分割成字符串集合

(类似: ( organization:create Or organization:update ) OR  NOT organization:delete  

就可以分割成[(, organization:create, Or, organization:update, ), OR, , NOT, organization:delete]这样的集合 

2.然后将该集合转换为逆波兰表达式(此处将操作符做了忽略大小写的操作):

(上例就可以转换为:[organization:create, organization:update, or, organization:delete, not, or]

3.再将其中除了操作符以外的权限字符串,用shiro的验证方法转为true  或者是  false

(转换为:[false, true, or, true, not, or]

4.然后再求最终逆波兰表达式的值,大功告成!

 

上代码:

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created by KisChang on 15-8-10.
 * hasPermission支持复杂表达式(使用逆波兰表达式计算)
 */
public abstract class OperatorAuthorizingRealmWithRpn extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(OperatorAuthorizingRealmWithRpn.class);

    //支持的运算符和运算符优先级
    public static final Map<String, Integer> expMap = new HashMap<String, Integer>(){{
        put("not",0);
        put("!"  ,0);

        put("and",0);
        put("&&" ,0);

        put("or" ,0);
        put("||" ,0);

        put("("  ,1);
        put(")"  ,1);
    }};

    public static final Set<String> expList = expMap.keySet();

    public OperatorAuthorizingRealmWithRpn() {
    }

    public OperatorAuthorizingRealmWithRpn(CacheManager cacheManager) {
        super(cacheManager);
    }

    public OperatorAuthorizingRealmWithRpn(CredentialsMatcher matcher) {
        super(matcher);
    }

    public OperatorAuthorizingRealmWithRpn(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }

    @Override
    public boolean isPermitted(PrincipalCollection principals, String permission) {
        Stack<String> exp = getExp(expList, permission);
        if (exp.size() == 1){
            return super.isPermitted(principals, exp.pop());
        }
        List<String> expTemp = new ArrayList<>();
        //将其中的权限字符串解析成true , false
        for(String temp : exp){
            if (expList.contains(temp)){
                expTemp.add(temp);
            }else{
                expTemp.add(Boolean.toString(super.isPermitted(principals, temp)) );
            }
        }
        logger.debug("permission:{}  Rpn:{}  parse:{}", permission, exp, expTemp);
        //计算逆波兰
        return computeRpn(expList, expTemp);
    }


    private static boolean computeRpn(Collection<String> expList,Collection<String> exp){
        logger.debug("RPN  exp :{}", exp);
        Stack<Boolean> stack = new Stack<>();
        for(String temp : exp){
            if (expList.contains(temp)){
                if ("!".equals(temp) || "not".equals(temp)){
                    stack.push( !stack.pop() );
                }else if ("and".equals(temp) || "&&".equals(temp)){
                    Boolean s1 = stack.pop();
                    Boolean s2 = stack.pop();
                    stack.push(s1 && s2);
                }else{
                    Boolean s1 = stack.pop();
                    Boolean s2 = stack.pop();
                    stack.push(s1 || s2);
                }
            }else{
                stack.push(Boolean.parseBoolean(temp));
            }
        }
        if (stack.size() > 1){
            logger.error("computeRpn RESULT ERROR>{}  exp:{}", stack, exp);
            throw new RuntimeException("compute error! stack: "+ exp.toString());
        }else{
            logger.debug("computeRpn RESULT SUCCESS>{}" , stack);
            return stack.pop();
        }
    }

    //获得逆波兰表达式
    private static Stack<String> getExp(Collection<String> expList, String exp) {
        Stack<String> s1 = new Stack<>();
        Stack<String> s2 = new Stack<>();
        for (String str : exp.split(" ")){
            str = str.trim();
            String strL = str.toLowerCase();
            if ("".equals(str)){
                continue;
            }
            if ("(".equals(str)){
                //左括号
                s1.push(str);
            }else if (")".equals(str)){
                //右括号
                while(!s1.empty()){
                    String temp = s1.pop();
                    if ("(".equals(temp)){
                        break;
                    }else{
                        s2.push(temp);
                    }
                }
            }else if(expList.contains(strL)){
                //操作符
                if (s1.empty()){
                    s1.push(strL);
                }else {
                    String temp = s1.peek();
                    if ("(".equals(temp) || ")".equals(temp)){
                        s1.push(strL);
                    }else if(expMap.get(strL) >= expMap.get(temp)){
                        s1.push(strL);
                    }else{
                        s2.push(s1.pop());
                        s1.push(strL);
                    }
                }
            }else{
                //运算数
                s2.push(str);
            }
        }
        while(!s1.empty()){
            s2.push(s1.pop());
        }
        return s2;
    }
}

 

 

只要将自己实现的userRealm 改为继承自上面这个类,就可以实现了!

 

第一次写博客,有什么错误欢迎指出。另外代码可能写的也不算多好,或是暗含bug(至少我简单测试了一下没有问题),希望大家指正!

 

 

分享到:
评论

相关推荐

    vue与shiro结合实现权限按钮

    Vue.js作为一个轻量级的前端框架,搭配Apache Shiro这样的安全管理框架,可以有效地实现前端的细粒度权限管理,如按钮级别的权限控制。本文将详细介绍如何在Vue项目中结合Shiro实现这一功能,以及所需的前置技术。 ...

    SpringBoot 集成 Shiro 实现动态uri权限

    SpringBoot集成Shiro实现动态URI权限是一个常见的权限管理实践,主要目的是为了实现更灵活、更安全的用户访问控制。在Web应用中,权限控制通常包括角色管理、菜单管理、操作权限(URI)管理等,而动态URI权限则允许...

    SpringBoot + shiro Demo 简单登录验证权限验证

    这个Demo提供了一个使用SpringBoot和Shiro实现简单登录验证和权限控制的实例,对于学习和理解这两个框架的集成非常有帮助。通过阅读和实践这个Demo,开发者可以更好地掌握如何在实际项目中应用SpringBoot的便捷性和...

    SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录

    SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 ...

    基于Shiro 拦截URL,实现权限控制

    除了基础的URL拦截,Shiro还提供了丰富的API和扩展点,允许开发者自定义复杂的权限逻辑,比如基于业务规则的动态权限控制。同时,Shiro的灵活性使得它可以很好地与其他框架(如Spring Boot、MyBatis等)集成,实现...

    shiro实现授权登陆验证

    在这个项目中,我们将会深入理解如何利用Shiro来实现登录验证和权限控制。 首先,我们要理解Shiro的核心组件。`Subject`是Shiro的中心概念,它代表了当前的用户或“安全主体”。`Realms`是Shiro与应用数据源交互的...

    springMVC+shiro实现动态权限验证.zip

    springMVC+shiro实现动态权限验证,实现动态设置用户角色,根据角色来决定哪些url可以访问 抱歉了各位需要修改下配置文件(org.eclipse.wst.common.component) &lt;?xml version="1.0" encoding="UTF-8"?&gt; ...

    SSM+Shiro实现权限角色控制

    SSM+Shiro框架组合是Java Web开发中常见的权限管理和安全控制解决方案,它结合了Spring、Spring MVC和MyBatis三大框架与Apache Shiro的安全库。这个项目利用这些技术实现了一个具备角色和权限控制功能的系统,使得...

    基于shiro前后端分离分布式权限管理(完整后端代码)

    本文将深入探讨基于Apache Shiro实现的前后端分离的分布式权限管理系统,结合Redis集群进行缓存管理的详细知识点。 首先,Apache Shiro是一个强大且易用的Java安全框架,主要用于身份认证、授权(权限控制)和会话...

    SpringBoot 整合 Shiro,实现从数据库加载权限、权限的动态更新、Session共享

    然后是Apache Shiro,这是一个强大且易于使用的Java安全框架,提供了身份验证(登录)、授权(权限管理)、会话管理和加密等核心功能。Shiro能够直接与应用程序代码集成,使得安全控制更加直观和简单。 1. **从...

    SSM+Shiro+redis实现的权限系统

    SSM+Shiro+Redis实现的权限系统是一个常见的企业级应用架构,主要用于构建安全、高效且可扩展的Web应用程序。这个系统结合了Spring、SpringMVC、MyBatis三大核心框架,以及Apache Shiro安全框架和Redis缓存技术,以...

    Shiro根据用户权限显示不同的菜单.Shiro根据权限显示指定菜单

    在这个场景中,我们关注的是如何利用Shiro实现根据用户权限动态显示不同的菜单。 首先,理解Shiro的核心概念是关键。在Shiro中,权限分为角色(Role)和权限(Permission)。角色是一组权限的集合,权限则具体描述...

    spring boot+shiro 权限认证管理案例

    Spring Boot 和 Apache Shiro 的整合是企业级应用中常见的权限认证和安全管理方案。Spring Boot 提供了简化 Java 应用程序...在实际开发中,还可以根据需求扩展 Shiro 功能,例如集成 JWT 认证、实现动态权限控制等。

    SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建.zip

    在IT毕业设计中,我们经常会遇到构建一个具备权限管理功能的系统,这通常涉及到基于角色的权限访问控制(Role-Based Access Control,简称RBAC)。在这个项目中,我们将使用SpringBoot框架与Apache Shiro库来实现...

    spring+shiro 增删改查权限控制

    当我们谈论“spring+shiro 增删改查权限控制”时,我们实际上是在讨论如何利用这两个框架实现对应用程序数据操作的权限管理和用户认证。 首先,Spring框架提供了模型-视图-控制器(MVC)架构模式,使得开发者可以更...

    ssm整合shiro实现用户权限验证的增删改查实例demo.zip

    本实例将详细解释如何将Shiro与SSM进行整合,实现用户权限验证的增删改查功能。 首先,我们需要理解SSM框架的基础。Spring是核心容器,负责管理对象(如Bean)的生命周期和依赖注入。SpringMVC作为Spring的Web MVC...

    shiro实现单点登录

    Apache Shiro是一个强大且易用的Java安全框架,提供了认证、授权、会话管理和加密等功能,非常适合用来实现SSO。在Spring框架基础上整合Shiro、Spring Data Redis以及Spring Session Data Redis,可以构建一个高效、...

    sprinbgboot实现的shiro权限验证源码

    分布式架构实现,基于springboot的shiro权限验证源码,包括redis,activeMq以及邮件通知等,websocket通信,mybatis链接数据库,完整的权限验证架构。

    springboot集成jwt和shiro实现前后端分离权限demo2

    而JWT(JSON Web Token)和Shiro是两个常用于权限管理的工具,它们能够帮助我们构建安全的、基于令牌的身份验证系统。本文将详细介绍如何在Spring Boot项目中集成JWT和Shiro,以及如何处理Realm中的异常。 首先,...

    Springboot+Shiro+Redis实现RBAC用户权限管理

    总结来说,"Springboot+Shiro+Redis实现RBAC用户权限管理"是一种高效、可扩展的解决方案,它结合了Springboot的便捷性、Shiro的权限管理功能和Redis的高速缓存能力,通过org.creazycake插件进一步简化了整合过程。...

Global site tag (gtag.js) - Google Analytics