`
jinnianshilongnian
  • 浏览: 21433412 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2404875
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:2997548
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5631359
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:257535
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1593116
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:248952
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5847389
Group-logo
跟我学Nginx+Lua开...
浏览量:698077
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:780398
社区版块
存档分类
最新评论

简单shiro扩展实现NOT、AND、OR权限验证

 
阅读更多

使用过shiro的朋友应该都知道在要想实现any permission的验证是比较麻烦。

 

很多朋友刚开始接触时以为如<shiro:hasPermission name="showcase:tree:*"> 代表验证拥有任何权限,但这是错误的。如果我们把showcase:tree:*授权给用户,那么此时表示用户具有showcase:tree资源的任意权限,如<shiro:hasPermission name="showcase:tree:*">或shiro:hasPermission name="showcase:tree:create">都能验证成功。

 

还有朋友认为<shiro:hasPermission name="showcase:tree:create,update"> 是或的关系,也不是,默认是且的关系。

 

下载了最新的shiro1.3.0-SNAPSHOT 发现并没有增加新的标签或其他支持。

 

因此我们需要简单的扩展下shiro来支持像spring security 3那样的@Secured支持表达式的强大注解。

 

不过有人已经提交了一个基于ANTLR实现的@Secured,可以在其JIRA上找到,在其官网的[ Version 2 Brainstorming ]也介绍并探讨了使用ANTLR语法的@Secured注解,可能在为了shiro 2版本添加进去,估计还得大半年,现在是1.3.0-SNAPSHOT。

 

对于我而言暂时不需要那么复杂的。因此暂时考虑扩展下默认的实现,在不添加任何注解/标签的基础上,简单的支持NOT、AND、OR即可。因此我们扩展AuthorizingRealm,并修改:

 

    private static final String OR_OPERATOR = " or ";
    private static final String AND_OPERATOR = " and ";
    private static final String NOT_OPERATOR = "not ";
    /**
     * 支持or and not 关键词  不支持and or混用
     * @param principals
     * @param permission
     * @return
     */
    public boolean isPermitted(PrincipalCollection principals, String permission) {
        if(permission.contains(OR_OPERATOR)) {
            String[] permissions = permission.split(OR_OPERATOR);
            for(String orPermission : permissions) {
                if(isPermittedWithNotOperator(principals, orPermission)) {
                    return true;
                }
            }
            return false;
        } else if(permission.contains(AND_OPERATOR)) {
            String[] permissions = permission.split(AND_OPERATOR);
            for(String orPermission : permissions) {
                if(!isPermittedWithNotOperator(principals, orPermission)) {
                    return false;
                }
            }
            return true;
        } else {
            return isPermittedWithNotOperator(principals, permission);
        }
    }

    private boolean isPermittedWithNotOperator(PrincipalCollection principals, String permission) {
        if(permission.startsWith(NOT_OPERATOR)) {
            return !super.isPermitted(principals, permission.substring(NOT_OPERATOR.length()));
        } else {
            return super.isPermitted(principals, permission);
        }
    }

 

如上代码即可以实现简单的NOT、AND、OR支持,不过缺点是不支持复杂的如AND、OR组合。

 

这样我就可以像如下使用了,不需要额外的标签,就是太长,如果实现如showcase:tree:(create|update|delete)这种语法相对而言简单多了,希望未来官网支持更好的方式:

<shiro:hasPermission name="showcase:tree:create or showcase:tree:update or showcase:tree:delete">

 

shiro总起来说使用起来还是比较舒服的,就是更新太慢。。。。

 

17
9
分享到:
评论
17 楼 java_zhenke 2015-06-17  
今天发现一个小坑,我在页面很多按钮加上shiro.hasPermission来划分权限,忘记在自己的Realm实现对应的spring-shiro.xml中配置缓存:
<bean id="shiroRealm" class="com.dc.web.realm.ShiroRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
<property name="cachingEnabled" value="true" />
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
</bean>
结果shiro每次遇到hasPermission都会去自己的ShiroRealm中执行一次doGetAuthorizationInfo,造成每次都得去执行一堆验证和取权限的SQL,页面响应时间都会受到影响。
16 楼 Dead_knight 2013-12-11  
jinnianshilongnian 写道
happylouis 写道
如果用户有权限:添加A---2;删除B---3;修改B---4
那用户的权限值 purview =2^2+2^3+2^4=28,也就是2的权的和了。
化成二进制可以表示为11100
这样,如果要验证用户是否有删除B的权限,就可以通过位与运算来实现。
即是:int value = purview &((int)Math.pow(2,3));
你会发现,当用户有操作权限时,运算出来的结果都会等于这个操作需要的权限值!


原理:
以上面的式子为例:purview & 2^3 也就是 28&8
将它们化成二进制有
  11100
& 01000
-------------------
  01000 == 8(十进制) == 2^3

请教楼主,这个权限算法用shiro要如何实现呢

先要明确一下;shiro默认实现都是进行字符串匹配;你这种的话;需要重写自己的AuthorizingRealm;这里有个很大的问题就是比如shiro支持:user--等价于--user:*,所以这种情况比较棘手,shiro本身默认实现都是基于字符串匹配;所以你要重写整个shiro的相关实现(最主要的就是AuthorizingRealm);然后权限字符串需要是如:资源:权限,其中权限不能省略; 这样的话你首先得到最后一个权限字符串;转换成数字;然后进行运算;如果成功返回true即可;

这种比字符串匹配感觉麻烦多了;不让字符串来的直观;效率也不会差很多。


我个人觉得没必要纠结于权限匹配算法。因为这个权限是自身项目的匹配算法,而shiro自己会帮你匹配的,所以这个算法根本不需要。
我的思路是:
1、自定义资源-权限的映射关系,那么你添加到元数据里面的就是[添加A,2]这样的映射。参考:
http://git.oschina.net/yuqs/snaker-demo/blob/master/src/main/java/org/snaker/framework/security/shiro/ShiroDefinitionSectionMetaSource.java
2、用户登录的时候,加载拥有的权限列表,而你的是权值,则需要换算之后再添加。即你要解决的是把28拆开成:2^2+2^3+2^4,然后每组除以2,再进行添加,即["2","3","4"]参考:
http://git.oschina.net/yuqs/snaker-demo/blob/master/src/main/java/org/snaker/framework/security/shiro/ShiroAuthorizingRealm.java
或者第一步添加的数据是:[添加A,(2,3)]
第二部只要把28拆开成2^2+2^3+2^4,然后每组格式为为(2,2),(2,3),(2,4)这样的

我的只是个思路,感觉都要对28进行拆
15 楼 jinnianshilongnian 2013-12-11  
happylouis 写道
如果用户有权限:添加A---2;删除B---3;修改B---4
那用户的权限值 purview =2^2+2^3+2^4=28,也就是2的权的和了。
化成二进制可以表示为11100
这样,如果要验证用户是否有删除B的权限,就可以通过位与运算来实现。
即是:int value = purview &((int)Math.pow(2,3));
你会发现,当用户有操作权限时,运算出来的结果都会等于这个操作需要的权限值!


原理:
以上面的式子为例:purview & 2^3 也就是 28&8
将它们化成二进制有
  11100
& 01000
-------------------
  01000 == 8(十进制) == 2^3

请教楼主,这个权限算法用shiro要如何实现呢

先要明确一下;shiro默认实现都是进行字符串匹配;你这种的话;需要重写自己的AuthorizingRealm;这里有个很大的问题就是比如shiro支持:user--等价于--user:*,所以这种情况比较棘手,shiro本身默认实现都是基于字符串匹配;所以你要重写整个shiro的相关实现(最主要的就是AuthorizingRealm);然后权限字符串需要是如:资源:权限,其中权限不能省略; 这样的话你首先得到最后一个权限字符串;转换成数字;然后进行运算;如果成功返回true即可;

这种比字符串匹配感觉麻烦多了;不让字符串来的直观;效率也不会差很多。

14 楼 happylouis 2013-12-11  
如果用户有权限:添加A---2;删除B---3;修改B---4
那用户的权限值 purview =2^2+2^3+2^4=28,也就是2的权的和了。
化成二进制可以表示为11100
这样,如果要验证用户是否有删除B的权限,就可以通过位与运算来实现。
即是:int value = purview &((int)Math.pow(2,3));
你会发现,当用户有操作权限时,运算出来的结果都会等于这个操作需要的权限值!


原理:
以上面的式子为例:purview & 2^3 也就是 28&8
将它们化成二进制有
  11100
& 01000
-------------------
  01000 == 8(十进制) == 2^3

请教楼主,这个权限算法用shiro要如何实现呢
13 楼 jinnianshilongnian 2013-05-23  
q474818917 写道
<!-- Shiro's main business-tier object for web-enabled applications -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="sessionMode" value="native"/>
		<property name="realm" ref="shiroDbRealm" /> 
		<property name="cacheManager" ref="shiroEhcacheManager" />
	</bean>
	
	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="sessionDAO" ref="sessionDAO"/>
	</bean>
	<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
		<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
	</bean>

我这样是不是指定了cache name了?可是我还是获取不到,又来寻求您帮助了

这个是activeSessionsCacheName  session的 不是验证的

你需要给realm加  有两个
1、权限的
2、用户的
12 楼 q474818917 2013-05-23  
<!-- Shiro's main business-tier object for web-enabled applications -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="sessionMode" value="native"/>
		<property name="realm" ref="shiroDbRealm" /> 
		<property name="cacheManager" ref="shiroEhcacheManager" />
	</bean>
	
	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="sessionDAO" ref="sessionDAO"/>
	</bean>
	<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
		<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
	</bean>

我这样是不是指定了cache name了?可是我还是获取不到,又来寻求您帮助了
11 楼 jinnianshilongnian 2013-05-22  
q474818917 写道
jinnianshilongnian 写道
q474818917 写道
我想问您个问题:
我动态的修改了用户的角色,怎么才能让该用户获取新的permission
也就是前台has_permission

这是你查询的问题:
一般的方案是:
1、第一个查出来缓存
2、如果修改了权限 则清空缓存 下次重新查

我看了一下,它是用ehcache做缓存的,但是我getAuthorizationCache这个居然没取到Cache
,不知道怎么回事

你需要自己配置上cache name 然后他按照principals去取。

不过不建议你使用这个 建议直接自己弄个切面 进行缓存  这样可以更好的控制缓存的过期等
10 楼 q474818917 2013-05-22  
jinnianshilongnian 写道
q474818917 写道
我想问您个问题:
我动态的修改了用户的角色,怎么才能让该用户获取新的permission
也就是前台has_permission

这是你查询的问题:
一般的方案是:
1、第一个查出来缓存
2、如果修改了权限 则清空缓存 下次重新查

我看了一下,它是用ehcache做缓存的,但是我getAuthorizationCache这个居然没取到Cache
,不知道怎么回事
9 楼 jinnianshilongnian 2013-05-22  
q474818917 写道
我想问您个问题:
我动态的修改了用户的角色,怎么才能让该用户获取新的permission
也就是前台has_permission

这是你查询的问题:
一般的方案是:
1、第一个查出来缓存
2、如果修改了权限 则清空缓存 下次重新查
8 楼 q474818917 2013-05-22  
我想问您个问题:
我动态的修改了用户的角色,怎么才能让该用户获取新的permission
也就是前台has_permission
7 楼 jinnianshilongnian 2013-05-09  
Dead_knight 写道
jinnianshilongnian 写道
semmy 写道
支持来个shiro专题系列

shiro使用起来确实比spring security简单多了 而且支持比较优秀的基于资源的权限验证,这样可维护性要好很多  后续可能介绍shiro 不过时间啊 时间

昨天看到你建议我出个shiro的专题。看到你已经写了两篇shiro的,顶一个。
shiro也研究过的,只是没有新的正式项目实际用到shiro,所以不便误导别人(特别是想正式使用shiro的)。不过现在网上shiro的资料也不少,springside4也把shiro整合进去了,完全可以参考,呵呵

我的这个就是使用中遇到的问题记录下来  shiro缺点就是更新比较慢 比不了spring这个庞然大物
6 楼 Dead_knight 2013-05-09  
jinnianshilongnian 写道
semmy 写道
支持来个shiro专题系列

shiro使用起来确实比spring security简单多了 而且支持比较优秀的基于资源的权限验证,这样可维护性要好很多  后续可能介绍shiro 不过时间啊 时间

昨天看到你建议我出个shiro的专题。看到你已经写了两篇shiro的,顶一个。
shiro也研究过的,只是没有新的正式项目实际用到shiro,所以不便误导别人(特别是想正式使用shiro的)。不过现在网上shiro的资料也不少,springside4也把shiro整合进去了,完全可以参考,呵呵
5 楼 jinnianshilongnian 2013-05-09  
semmy 写道
支持来个shiro专题系列

shiro使用起来确实比spring security简单多了 而且支持比较优秀的基于资源的权限验证,这样可维护性要好很多  后续可能介绍shiro 不过时间啊 时间
4 楼 semmy 2013-05-09  
支持来个shiro专题系列
3 楼 jinnianshilongnian 2013-05-09  
rekoe.net 写道
这个类如何生效?

不过官网jira给出更强大的实现 使用antlr做语法分析 不过需要添加好多东西,如果不需要那么麻烦 还是这样简单点
2 楼 jinnianshilongnian 2013-05-09  
rekoe.net 写道
这个类如何生效?

我们在实现shiro的时候如果不用JdbcRealm, 都要自己实现一个,或者覆盖JdbcRealm,或者实现AuthorizingRealm等,此时覆盖其isPermitted(PrincipalCollection principals, String permission) 即可 
1 楼 rekoe.net 2013-05-09  
这个类如何生效?

相关推荐

Global site tag (gtag.js) - Google Analytics