在第一部分,使用shiro主要做了基于url的登陸攔截,但是在真正的生產(chǎn)環(huán)境下往往是注解,標(biāo)簽等綜合使用,以下是基于注解和標(biāo)簽的代碼筆記
URL攔截權(quán)限控制是基于過(guò)濾器或者攔截器的
方法注解權(quán)限控制是基于代理(action代理)
【1】spring配置中開(kāi)啟shiro注解
<!-- 開(kāi)啟shiro注解 -->
<bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!-- 強(qiáng)制使用cglib為Action創(chuàng)建代理對(duì)象() -->
<property name="proxyTargetClass" value="true"></property>
</bean>
<!-- 切面類 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
注意:這里最好開(kāi)啟cglib代理(產(chǎn)生的是子類對(duì)象),默認(rèn)是jdk代理(新的代理對(duì)象)
知識(shí)拓展:
1.JDK動(dòng)態(tài)代理
此時(shí)代理對(duì)象和目標(biāo)對(duì)象實(shí)現(xiàn)了相同的接口
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是針對(duì)類實(shí)現(xiàn)代理,主要是對(duì)指定的類生成一個(gè)子類
具體查看:http://blog.csdn.net/cpzhong/article/details/6423333
另外注意:這里如果使用shiro了,在action中的baseAction就不能直接強(qiáng)轉(zhuǎn)了,因?yàn)槿绻莏dk代理是action的新代理對(duì)象,而非action對(duì)象或者子類對(duì)象,所以強(qiáng)轉(zhuǎn)會(huì)報(bào)錯(cuò),這也是為什么要使用cglib代理的原因。
【2】方法上使用權(quán)限注解
/**
* 刪除派遣員
* @return
*/
@RequiresPermissions(value="staff11")//執(zhí)行當(dāng)前方法需要具有staff權(quán)限
//@RequiresRoles(value="staff")//執(zhí)行當(dāng)前方法需要具有staff角色
public String delete(){
staffService.deleteBatch(ids);
/**
* 當(dāng)權(quán)限或者角色任意一個(gè)不滿足都會(huì)拋出org.apache.shiro.authz.UnauthorizedException:
* 異常,所以需要我們做公共異常捕獲,在struts配置文件中配置公共異常捕獲頁(yè)面
*/
return "list";
}
【3】Realm中授權(quán)
在bosReaml的授權(quán)方法中授予相應(yīng)權(quán)限
/**
* 授權(quán)方法(這個(gè)用戶有什么權(quán)限)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("進(jìn)入授權(quán)方法... ...");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("staff");//為當(dāng)前用戶授予staff權(quán)限
//TODO 根據(jù)當(dāng)前登錄用戶查詢數(shù)據(jù)庫(kù),獲取其對(duì)應(yīng)的權(quán)限數(shù)據(jù)
return info;
}
【4】訪問(wèn)查看
(當(dāng)授權(quán)是staff11是會(huì)正常操作刪除方法,當(dāng)授權(quán)非staff11時(shí),我們分別授權(quán)staff11和staff,發(fā)現(xiàn)staff會(huì)報(bào)錯(cuò),拋出異常org.apache.shiro.authz.UnauthorizedException)
當(dāng)shiro使用注解時(shí),遇到權(quán)限和角色不足時(shí)均會(huì)拋出org.apache.shiro.authz.UnauthorizedException異常,所以這里需要捕獲處理
【5】struts中配置全局異常處理
<global-results>
<result name="login">/login.jsp</result>
<result name="unauthorizedUrl">/unauthorizedUrl.jsp</result>
</global-results>
<!-- 指定全局異常捕獲 -->
<!-- 當(dāng)出現(xiàn)權(quán)限異常進(jìn)行捕獲,并返回至unauthorizedUrl.jsp-->
<global-exception-mappings>
<exception-mapping result="unauthorizedUrl"
exception="org.apache.shiro.authz.AuthorizationException"></exception-mapping>
</global-exception-mappings>
修改后
使用標(biāo)簽進(jìn)行資源控制
【1】jsp頁(yè)面引入shiro標(biāo)簽
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
【2】對(duì)需要權(quán)限攔截的菜單 按鈕進(jìn)行攔截添加
這里主要shiro標(biāo)簽可以直接包html代碼,也可以直接包js代碼
//工具欄(給刪除安全添加權(quán)限攔截)
var toolbar = [ {
id : 'button-view',
text : '查詢',
iconCls : 'icon-search',
handler : doView
}, {
id : 'button-add',
text : '增加',
iconCls : 'icon-add',
handler : doAdd
}, <shiro:hasPermission name="staff">{
id : 'button-delete',
text : '作廢',
iconCls : 'icon-cancel',
handler : doDelete
},</shiro:hasPermission>{
id : 'button-save',
text : '還原',
iconCls : 'icon-save',
handler : doRestore
}];
注意:<shiro:hasPermission name="staff11">表示只有擁有staff11權(quán)限的用戶才會(huì)顯示該按鈕
前后對(duì)比
【通過(guò)查詢數(shù)據(jù)庫(kù),進(jìn)行用戶授權(quán)】
修改自定義Realm的授權(quán)方法
/**
* 授權(quán)方法(這個(gè)用戶有什么權(quán)限)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("進(jìn)入授權(quán)方法... ...");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//info.addStringPermission("staff");//為當(dāng)前用戶授予staff權(quán)限
//info.addRole("staff");//為當(dāng)前用戶授予staff角色(角色是權(quán)限的集合)
//TODO 根據(jù)當(dāng)前登錄用戶查詢數(shù)據(jù)庫(kù),獲取其對(duì)應(yīng)的權(quán)限數(shù)據(jù)
//獲取當(dāng)前用戶
User user = (User) principals.getPrimaryPrincipal();
List<Function> list = null;
if(user.getUsername().equals("admin")){
//超級(jí)管理員(查詢所有權(quán)限)
list = functionDao.findAll();
}else{
//普通用戶(查詢擁有權(quán)限)
list = functionDao.findListByuserId(user.getId());
}
//授權(quán)
for(Function function : list){
info.addStringPermission(function.getCode());
}
return info;
}