Acegi: Authz标签在有的情况下不起作用

阅读更多
问题描述:Acegi的标签库配置正确,而中ifAllGranted和ifAnyGranted都不起作用,但是ifNotGranted起作用。
解决方法:查看web.xml,把Acegi的Filter调到最前面。比如有sitemesh的filter,也有acegi的,一定要把acegi的放在前面。

今天晚上被Acegi的Tag Library折腾了2个小时。

事情是这样的,本来想用Acegi的标签库来判断用户角色并显示相应的链接,比如说
xml 代码
 
  1. <authz:authorize ifAllGranted="ANONYMOUS">  
  2.   <span><a href="<%=request.getContextPath()%>/jsp/user/register.jsp">注册a> span>  
  3.   <span><a href="<%=request.getContextPath()%>/jsp/index.jsp">登录a> span>  
  4. authz:authorize>  
  5. <authz:authorize ifAnyGranted="ADMIN,USER">  
  6.   <span class="last"><a href="<%=request.getContextPath()%>/logout.htm">注销a> span>  
  7. authz:authorize>  


authz的用法就不介绍了,文档讲的比较明白,意思也很明了。上面的代码就是说当当前用户是ANONYMOUS权限的时候,就显示登录和注册链接,当当前用户是管理员或者普通用户的时候,就显示注销链接。

于是在taglib.jsp里面加入了
xml 代码
 
  1. <%@ taglib prefix="authz" uri="http://acegisecurity.org/authz" %>  

就应该可以用啦。但是很奇怪,上面两个好像都不起作用。用ifNotGranted却好用。这就怪了,难道还分方法的?于是把AcegiSecurity的源码找出来,开始追根溯源。

对应的是AuthorizeTag.java,当然,主要是doStartTag方法。基本的逻辑是这样,先获得当前用户的Authentication,然后获得页面中属性的内容,然后比较,如果符合,则显示标签里面的内容,否则跳过标签的内容。

调试看了看,发现页面上的内容都获得到了,但是最后却return Tag.SKIP_BODY;了,那就应该是获得当前用户的Authentication的时候出错了。经过艰难的调试,发现匿名的时候,

java 代码
  1. Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();  


中,currentUser居然是null。而我同时在另一个类里面却能获得ANONYMOUS。又打印SecurityContextHolder.getContext(),也是Null Authentication,无语了,完全一样的用法啊?查了查Acegi的文档,说SecurityContextHolder使用一个ThreadLocal来保存,难道页面的标签库和Spring中的一些类属于不同thread?但是我打印Thread.currentThread又是一样的。。。

后来在spring的论坛上搜索到类似问题,“Authz tags do not work in JSPs under certain condition”(http://forum.springframework.org/showthread.php?t=32189),才找到问题的所在,问题解决人说:

Filter order is important, we know that, it's drummed in by Acegi docs and forum posts left right and centre. But (for me at least) you just focus on the FilterChainProxy. However, before Acegi gets hold of any requests the web.xml must hand them over. Filter order is declared there too and is explicit in the order of your declarations, so if like me you also have a filter for your action/controller framework, then this must be declared after (below) the Acegi one.

果然,把我在web.xml中的sitemesh的filter放到acegi的filter后面之后,问题就解决了。

至于为什么会导致SecurityContextHolder.getContext()的不同,我想应该是sitemesh先Filter,先走到页面那一块,Authz已经执行了,但这个时候同样的页面还没被Acegi的Filter拦截,所以就出现了上面的问题(个人理解,待验证)。

你可能感兴趣的:(Acegi,Web,freemarker,JSP,XML)