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