ACEGI标签
虽然Acegi的安全强制过滤器能够阻止用户浏览他们没有权限看到的页面,但最好的做法是从一开始就不提供指向受限制页面的链接。<authz:authorize>标签能够根据当前用户是否拥有恰当权限来决定显示或隐藏Web页面的内容。
<authz:authorize>是一个流程控制标签,能够在满足特定安全需求的条件下显示它的内容体。它有三个互斥的参数:
n ifAllGranted——是一个由逗号分隔的权限列表,用户必须拥有所有列出的权限才能渲染标签体;
n ifAnyGranted——是一个由逗号分隔的权限列表,用户必须至少拥有其中的一个才能渲染标签体;
n ifNotGranted——是一个由逗号分隔的权限列表,用户必须不拥有其中的任何一个才能渲染标签体。
你可以轻松地想像在JSP中如何使用< authz:authorize>标签根据用户的权限来限制他们的行为。例如,Spring培训应用有一个向用户显示课程有关信息的课程明细页面。 对管理员来说,如果能够从课程明细页面直接跳转到课程编辑页面从而可以更新课程信息是很方便的。但你不希望这个链接对除了管理员之外的其他用户可见。
使用<authz:authorize>标签,在用户没有管理员权限的情况下,你可以避免渲染到课程编辑页面的链接:
<authz:authorize ifAllGranted="ROLE_ADMINISTRATOR">
<a href="admin/editCourse.htm?courseId=${course.id}">
Edit Course
</a>
</authz:authorize>
这里,我们使用了ifAllGranted参数,由于这里只需要检查一个授权,所以ifAllGranted标签也是可以使用的。Web应用的安全性只是Acegi功能的一个方面。现在让我们考察它的另一面——保护方法调用。
扩展acegi标签实现动态定位方法对应的权限列表
实现如下:
package com.wonder.cdc.oa.webapp.taglib;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.taglibs.authz.AuthorizeTag;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.wonder.cdc.oa.service.security.AcegiCacheManager;
import com.wonder.cdc.oa.service.security.ResourceDetails;
/**
* 根据当前指定方法名称,判断当前用户是否有权限访问该标签方法体
* @author sudi
*/
public class AuthorizeFuncTag extends AuthorizeTag {
/**
* 扩展acegi标签,实现指定方法名称自动根据名称生成对应的权限字符序列传递给acegi对应的标签
*/
private static final long serialVersionUID = 1L;
private String funcString;
public String getFuncString() {
return funcString;
}
public void setFuncString(String funcString) {
this.funcString = funcString;
}
public int doStartTag() throws JspException {
//如果设置的funcString为空则显示标签体
if(StringUtils.isBlank(getFuncString())){
return EVAL_BODY_INCLUDE;
}
ServletContext context = pageContext.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
AcegiCacheManager acegiCacheManager = (AcegiCacheManager) ctx.getBean("acegiCacheManager");
GrantedAuthority[] authorities = new GrantedAuthority[0];
String roles = " ";
List functions = acegiCacheManager.getFunctions();
String funcString;
boolean findFlag = false;
for(int i = 0; i < functions.size(); i++){
funcString = ((String)functions.get(i)).trim();
if(funcString.equals(getFuncString())){
findFlag = true;
}
}
//如果设置的funcString没有在acegi的权限控制范围内则显示标签体
if(!findFlag){
return EVAL_BODY_INCLUDE;
}
//如果在acegi的权限控制范围则取出该资源相对应的权限设置到setIfAnyGranted()方法中
ResourceDetails rd = acegiCacheManager.getAuthorityFromCache(getFuncString());
if(rd != null){
authorities = rd.getAuthorities();
}
if (authorities.length > 0) {
for (int i = 0; i < authorities.length; i++) {
roles += authorities.getAuthority() + ",";
}
roles = roles.substring(0, roles.length() - 1);
}
this.setIfAnyGranted(roles);
return super.doStartTag();
}
}
标签描述文件:
<tag>
<name>isVisualable</name>
<tag-class>com.wonder.cdc.oa.webapp.taglib.AuthorizeFuncTag</tag-class>
<info>
根据当前指定方法名称,判断当前用户是否有权限访问该标签方法体
</info>
<attribute>
<name>funcString</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
其中的acegiCacheManager,是由spring来维护的,用来管理用户,角色,权限,资源的缓存管理类,
其与持久层是同步更新的,用以获得尽可能的性能提升。
acegi的url和method的访问控制都是基于数据库的,这样要比在xml中配置更灵活。
扩展前:
<authz:authorize ifAnyGranted="AUTH_ADMIN,AUTH_USER">
<input type="button" style="margin-right: 5px"
onclick="location.href='<c:url value="/editRole.html?method=Add&from=list"/>'"
value="<fmt:message key="button.add"/>"/>
</authz:authorize>
扩展后:
<CDC:isVisualable funcString="RoleManager.saveRole">
<input type="button" style="margin-right: 5px"
onclick="location.href='<c:url value="/editRole.html?method=Add&from=list"/>'"
value="<fmt:message key="button.add"/>"/>
</CDC:isVisualable>
可以看到,扩展前必须通过硬编码的方式指定当前用户是否有权限看到该按钮,而且一旦增加新的权限,就要对应修改所有的相关页面,要死人的阿...
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1752951