在SPRing Context中定義shiroFilter(org.apache.shiro.spring.web.ShiroFilterFactoryBean)時(shí)需要為其filterChainDefinitions property賦值,這個屬性是個chainName-to-chainDefinition map of chain definitions,用于為URL定義過濾策略。
比如:
/404.htm = anon/main!main.html = anon/**.html = perms[myPerm_1]
rest:比如/admins/user/**=rest[user],根據(jù)請求的方法,相當(dāng)于/admins/user/**=perms[user:method] ,其中method為post,get,delete等。
port:比如/admins/user/**=port[8081],當(dāng)請求的url的端口不是8081是跳轉(zhuǎn)到schemal://serverName:8081?queryString,其中schmal是協(xié)議http或https等,serverName是你訪問的host,8081是url配置里port的端口,queryString是你訪問的url里的?后面的參數(shù)。
perms:比如/admins/user/**=perms[user:add:*],perms參數(shù)可以寫多個,多個時(shí)必須加上引號,并且參數(shù)之間用逗號分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],當(dāng)有多個參數(shù)時(shí)必須每個參數(shù)都通過才通過,想當(dāng)于isPermitedAll()方法。
roles:比如/admins/user/**=roles[admin],參數(shù)可以寫多個,多個時(shí)必須加上引號,并且參數(shù)之間用逗號分割,當(dāng)有多個參數(shù)時(shí),比如/admins/user/**=roles["admin,guest"],每個參數(shù)通過才算通過,相當(dāng)于hasAllRoles()方法。
anon:比如/admins/**=anon 沒有參數(shù),表示可以匿名使用。authc:比如/admins/user/**=authc表示需要認(rèn)證才能使用,沒有參數(shù)authcBasic:比如/admins/user/**=authcBasic沒有參數(shù)表示httpBasic認(rèn)證ssl:比如/admins/user/**=ssl沒有參數(shù),表示安全的url請求,協(xié)議為httpsuser:比如/admins/user/**=user沒有參數(shù)表示必須存在用戶,當(dāng)?shù)侨氩僮鲿r(shí)不做檢查
一般情況下,我們可以將模塊作為一個粒度,例如:
/blog!**.html = user
偶爾也會有將每一個URL作為一個授權(quán)單位進(jìn)行控制,例如:
/blog!doAddNewArticle.html = authc,perms[addArticle]
但是URL的數(shù)量讓人頭疼,也許可以每開發(fā)一個功能的時(shí)候打開xml文件寫入U(xiǎn)RL然后同步到SVN,或者我們也可以找一個人專門做這些事情,無論是添加、刪除功能還是修改方法名都通知這個人去做...換位思考一下,我不希望我是這個人...
所以我要把這些URL放在數(shù)據(jù)庫進(jìn)行管理。我要把他們統(tǒng)統(tǒng)Query出來放到filterChainDefinitions里。我需要裝配一個Bean,實(shí)際上他是一個org.springframework.beans.factory.FactoryBean<Section>的實(shí)現(xiàn)。
<bean id="chainFilterBuff" class="king.common.ChainFilterBuff"> <property name="filterChainDefinitions"> /404.htm = anon /main!main.html = anon </property></bean>
然后將其注入:
<bean id="shiroFilter1" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/main!main.html" /> <property name="successUrl" value="/main!main.html" /> <property name="unauthorizedUrl" value="/unAuthorized.htm" /> <property name="filterChainDefinitionMap" ref="chainFilterBuff" /></bean>
java代碼中implements FactoryBean<Ini.Section>并實(shí)現(xiàn)需要Override的method,關(guān)鍵是getObject這個method:
private String filterChainDefinitions;@Overridepublic Section getObject() throws Exception { Ini ini = new Ini(); ini.load(filterChainDefinitions); //先載入XML中定義好的chain Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); /* * 省略讀取步驟 * 繼續(xù)加入數(shù)據(jù)庫中的chain * section.put("/**", "authc, roles[admin]"); */ return section;}等等,這些僅僅是定義了權(quán)限。我們需要在用戶訪問這些URL的時(shí)候去驗(yàn)證一下用戶是否具備當(dāng)前URL權(quán)限。所以我定義了(事實(shí)上我們必須定義一個Realm,ShiroFilterFactoryBean需要SecurityManager,而我們使用的SecurityManager的實(shí)現(xiàn)類DefaultWebSecurityManager則需要一個Realm!):
<bean id="shiroDataBaseRealm" class="king.security.KingMainRealm">
并且Override了接口定義的method:
public class KingMainRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo( //授權(quán) PrincipalCollection principals) { UserBean _user = (UserBean) principals.fromRealm(getName()).iterator().next(); SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); /* * 省略 */ return authInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo( //認(rèn)證 AuthenticationToken token) throws AuthenticationException { UserBean user = new UserBean(); UsernamePassWordToken userToken = (UsernamePasswordToken)token; user.setUserName(userToken.getUsername()); user.setPassword(userToken.getPassword()); return new SimpleAuthenticationInfo(user, user.getPassword(), getName()); }}若已定義了需要請求的URL,用戶登錄時(shí)doGetAuthorizationInfo會被調(diào)用,剩下的就是為每一個用戶管理這些權(quán)限了。也許我們可以創(chuàng)建角色關(guān)聯(lián)多個權(quán)限,用戶關(guān)聯(lián)多個角色,類似這樣的設(shè)置不同的層次。按自己喜歡的方式去做吧 :)
新聞熱點(diǎn)
疑難解答
圖片精選