博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单扩展shiro 实现NOT、AND、OR权限验证(支持复杂一点的表达式)
阅读量:7047 次
发布时间:2019-06-28

本文共 4513 字,大约阅读时间需要 15 分钟。

hot3.png

简单扩展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,以及&&、||、!

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

我先是看到了这篇博客:

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

于是便有了这篇文章

实现思路:

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
 expMap = new HashMap
(){
{        put("not",0);        put("!"  ,0);        put("and",0);        put("&&" ,0);        put("or" ,0);        put("||" ,0);        put("("  ,1);        put(")"  ,1);    }};    public static final Set
 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
 exp = getExp(expList, permission);        if (exp.size() == 1){            return super.isPermitted(principals, exp.pop());        }        List
 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
 expList,Collection
 exp){        logger.debug("RPN  exp :{}", exp);        Stack
 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
 getExp(Collection
 expList, String exp) {        Stack
 s1 = new Stack<>();        Stack
 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(至少我简单测试了一下没有问题),希望大家指正!

  

转载于:https://my.oschina.net/dreamlove/blog/490250

你可能感兴趣的文章
我的友情链接
查看>>
samba服务的用法及原理
查看>>
13.数据库连接池
查看>>
2.vi 和 vim 编辑器
查看>>
Another Array of Orz Pandas
查看>>
第5.6单元作业
查看>>
mdadm--RAID 5
查看>>
java异常设计
查看>>
服务器的几种时间同步
查看>>
我的友情链接
查看>>
WPF“动画序列”框架的初步研究与实现(附源码)
查看>>
校招求职面试连载(二)
查看>>
网络学习(三十一)操作系统无人值守自动安装之Windows XP
查看>>
handler 机制
查看>>
解决mysql无法导入本地文件的问题
查看>>
HBase 系统架构
查看>>
程序分析思路
查看>>
RichFace标签学习笔记
查看>>
iOS中block介绍(四)揭开神秘面纱(下)
查看>>
更改yum源为阿里云的yum源
查看>>