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

第九章 JSP标签——《跟我学Shiro》

阅读更多

 

目录贴: 跟我学Shiro目录贴

 

Shiro提供了JSTL标签用于在JSP/GSP页面进行权限控制,如根据登录用户显示相应的页面按钮。

 

 

导入标签库

<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

标签库定义在shiro-web.jar包下的META-INF/shiro.tld中定义。

 

guest标签 

<shiro:guest>
欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</shiro:guest> 

 

用户没有身份验证时显示相应信息,即游客访问信息。

 

user标签 

<shiro:user>
欢迎[<shiro:principal/>]登录,<a href="${pageContext.request.contextPath}/logout">退出</a>
</shiro:user> 

用户已经身份验证/记住我登录后显示相应的信息。

  

authenticated标签 

<shiro:authenticated>
    用户[<shiro:principal/>]已身份验证通过
</shiro:authenticated> 

用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。    

 

notAuthenticated标签

<shiro:notAuthenticated>
    未身份验证(包括记住我)
</shiro:notAuthenticated> 

用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。 

 

principal标签 

<shiro: principal/>

显示用户身份信息,默认调用Subject.getPrincipal()获取,即Primary Principal。

 

<shiro:principal type="java.lang.String"/>

相当于Subject.getPrincipals().oneByType(String.class)。 

 

<shiro:principal type="java.lang.String"/>

相当于Subject.getPrincipals().oneByType(String.class)。

 

<shiro:principal property="username"/>

相当于((User)Subject.getPrincipals()).getUsername()。   

 

hasRole标签 

<shiro:hasRole name="admin">
    用户[<shiro:principal/>]拥有角色admin<br/>
</shiro:hasRole> 

如果当前Subject有角色将显示body体内容。

 

hasAnyRoles标签 

<shiro:hasAnyRoles name="admin,user">
    用户[<shiro:principal/>]拥有角色admin或user<br/>
</shiro:hasAnyRoles> 

如果当前Subject有任意一个角色(或的关系)将显示body体内容。 

 

lacksRole标签 

<shiro:lacksRole name="abc">
    用户[<shiro:principal/>]没有角色abc<br/>
</shiro:lacksRole> 

如果当前Subject没有角色将显示body体内容。 

  

hasPermission标签

<shiro:hasPermission name="user:create">
    用户[<shiro:principal/>]拥有权限user:create<br/>
</shiro:hasPermission> 

如果当前Subject有权限将显示body体内容。 

  

lacksPermission标签

<shiro:lacksPermission name="org:create">
    用户[<shiro:principal/>]没有权限org:create<br/>
</shiro:lacksPermission> 

如果当前Subject没有权限将显示body体内容。

 

另外又提供了几个权限控制相关的标签:

 

导入自定义标签库 

<%@taglib prefix="zhang" tagdir="/WEB-INF/tags" %>

 

示例

<zhang:hasAllRoles name="admin,user">
    用户[<shiro:principal/>]拥有角色admin和user<br/>
</zhang:hasAllRoles>
<zhang:hasAllPermissions name="user:create,user:update">
    用户[<shiro:principal/>]拥有权限user:create和user:update<br/>
</zhang:hasAllPermissions>
<zhang:hasAnyPermissions name="user:create,abc:update">
    用户[<shiro:principal/>]拥有权限user:create或abc:update<br/>
</zhang:hasAnyPermissions> 

hasAllRoles表示拥有所有相关的角色;hasAllPermissions表示拥有所有相关的权限;hasAnyPermissions表示拥有任意一个相关的权限。

 

另外可以参考我的《简单shiro扩展实现NOT、AND、OR权限验证》实现NOT、AND、OR权限验证:http://jinnianshilongnian.iteye.com/blog/1864800

  

示例源代码:https://github.com/zhangkaitao/shiro-example;可加群 231889722 探讨Spring/Shiro技术。

 

16
6
分享到:
评论
12 楼 java_xh 2017-11-23  
感谢楼主,在处理system:user:* 语义的时候遇到点儿困难,之前我自己理解的是拥有system:user:下面任意一个权限就返回true,但是其实是满足所有权限才返回true,实际应用场景我更需要任意一个满足就返回true,所以我自己做了重新实现。

参照了源码,发现校验权限的方法实现主要是这两个
AuthorizingRealm.java 304行
protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
	Collection perms = this.getPermissions(info);
	if(perms != null && !perms.isEmpty()) {
		Iterator var4 = perms.iterator();

		while(var4.hasNext()) {
			Permission perm = (Permission)var4.next();
			if(perm.implies(permission)) {
				return true;
			}
		}
	}

	return false;
}

WildcardPermission.java 85行
public boolean implies(Permission p) {
	if(!(p instanceof WildcardPermission)) {
		return false;
	} else {
		WildcardPermission wp = (WildcardPermission)p;
		List otherParts = wp.getParts();
		int i = 0;

		for(Iterator part = otherParts.iterator(); part.hasNext(); ++i) {
			Set otherPart = (Set)part.next();
			if(this.getParts().size() - 1 < i) {
				return true;
			}

			Set part1 = (Set)this.getParts().get(i);
			if(!part1.contains("*") && !part1.containsAll(otherPart)) {
				return false;
			}
		}

		while(i < this.getParts().size()) {
			Set var8 = (Set)this.getParts().get(i);
			if(!var8.contains("*")) {
				return false;
			}

			++i;
		}

		return true;
	}
}

这里我要修改*号的实现逻辑,必须要重写implies方法,所以我自定义了自己的CustomerPermission类,实现了WildcardPermission,代码如下
public CustomerPermission(String permissionString) {
	super(permissionString, false);
}

/**
 * 将当前需要验证的权限和用户拥有的权限之一对比,惹大于则返回true<br>
 * 重写的目的是为了将user:*的语义更改为any,即满足user:下面任何一个权限即可(原语义为满足user:下面所有权限)<br>
 *
 * @param p 表示当前需要验证的权限,  this 表示用户拥有的权限之一
 * @return boolean
 */
@Override
public boolean implies(Permission p) {
	if(!(p instanceof CustomerPermission)) {
		return false;
	} else {
		CustomerPermission wp = (CustomerPermission)p;
		List otherParts = wp.getParts();
		int i = 0;

		for(Iterator part = otherParts.iterator(); part.hasNext(); ++i) {
			Set otherPart = (Set)part.next();
			if(this.getParts().size() - 1 < i) {
				return true;
			}

			// 这里就是重写的重点,表示当前需要验证的权限当前是*号,那么就可以匹配任意权限,所以可以直接返回true
			if (otherPart.contains("*")) {
				return true;
			}

			Set part1 = (Set)this.getParts().get(i);
			if(!part1.contains("*") && !part1.containsAll(otherPart)) {
				return false;
			}
		}

		while(i < this.getParts().size()) {
			Set var8 = (Set)this.getParts().get(i);
			if(!var8.contains("*")) {
				return false;
			}

			++i;
		}

		return true;
	}
}


后面的事情就是要去把shiro的默认使用的WildcardPermission替换为CustomerPermission的实例,重写PermissionResolver
public class CustomerPermissionResolver implements PermissionResolver {
    @Override
    public Permission resolvePermission(String permissionString) {
        return new CustomerPermission(permissionString);
    }
}


替换shiro默认的WildcardPermission为CustomerPermission一开始是采用楼主文档中的ini配置,如下:
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
permissionResolver=com.fc.realm.CustomerPermissionResolver
authorizer.permissionResolver=$permissionResolver
securityManager.authorizer=$authorizer

后来发现这种方式无法替换permissionResolver,是因为在AuthenticatingRealm类的构造函数中有一句写死的赋值语句
public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
	if(cacheManager != null) {
		this.setCacheManager(cacheManager);
	}

	if(matcher != null) {
		this.setCredentialsMatcher(matcher);
	}

	this.authorizationCachingEnabled = true;
	[color=red]this.permissionResolver = new WildcardPermissionResolver();[/color]
	int instanceNumber = INSTANCE_COUNT.getAndIncrement();
	this.authorizationCacheName = this.getClass().getName() + ".authorizationCache";
	if(instanceNumber > 0) {
		this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber;
	}

}


所以我在自定义的UserRealm类的构造函数中重新为该属性赋值了,即可达到效果,实现自己的权限校验逻辑
public UserRealm()
{
	super();
	// 这句话很重要,把自定义的PermissionResolver注入到AuthorizingRealm对象的permissionResolver中
	super.setPermissionResolver(new CustomerPermissionResolver());
}
11 楼 zj_璠璠 2017-03-03  
js中使用shiro好像无效
     
10 楼 德赫0625 2016-05-23  
notAuthenticated标签,这里的描述“用户已经身份验证通过”似乎写错了?应该是“用户身份未验证通过”吧
9 楼 xubao6000 2016-04-05  
为什么在页面之中引入<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>之后,加载速度从1-2秒变成 了大约1分钟左右呢?没有其它任何区别,只有引入标签的区别
8 楼 u011168185 2016-01-18  
我想请教一下,如果是html页面怎么办呢???
7 楼 u013609917 2016-01-15  
shiro 标签用js加好像无效   (菜鸟询问)
6 楼 sunwt 2014-05-08  
在sitemesh的decorator页面内使用shiro标签貌似不太好用啊~求解答
5 楼 freerambo 2014-05-07  
照着例子做了一天了,非常受用。 之处个小错误啊 在自定义标签中: hasAnyPermissions.tag 中,for循环中的判定条件 if(subject.isPermitted(permission)) ,一旦有一个命中就应该终止,我加的break; 否则的话会打印多次 jsp body


谢!!!taoge居然是非法字符。。。
4 楼 jinnianshilongnian 2014-03-06  
lyq881209 写道
jinnianshilongnian 写道
lyq881209 写道
问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。

1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;
2、cache会清除

session:用的是DefaultWebSessionManager,sessionDAO用的是继承AbstractSessionDAO的自定义类。
当subject.logout()或会话过期,需要自定义session监听器来手动清理吗。

实现SessionDAO 即可 你去看看它的api吧 里边有个doDelete方法
3 楼 lyq881209 2014-03-06  
jinnianshilongnian 写道
lyq881209 写道
问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。

1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;
2、cache会清除

session:用的是DefaultWebSessionManager,sessionDAO用的是继承AbstractSessionDAO的自定义类。
当subject.logout()或会话过期,需要自定义session监听器来手动清理吗。
2 楼 jinnianshilongnian 2014-03-06  
lyq881209 写道
问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。

1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;
2、cache会清除
1 楼 lyq881209 2014-03-06  
问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。

相关推荐

Global site tag (gtag.js) - Google Analytics