r即可。如果非常簡單的cookie,可以直接實現RememberMeManager的幾個接口方法也行
【Apache Shiro in Spring】自定義filterChainDefinitions和Realm
文章出處
在Spring Context中定義shiroFilter(org.apache.shiro.spring.web.ShiroFilterFactoryBean)時需要為其filterChainDefinitions property賦值,這個屬性是個chainName-to-chainDefinition map of chain definitions,用于為URL定義過濾策略。
filterChainDefinitions是一個set method,他調用setFilterChainDefinitionMap(section),FilterChainDefinitionMap是個Field。
比如,這是我定義的:
/404.htm = anon /main!main.html = anon /**.html = perms[myPerm_1]
在這里引用一下某前輩總結的chainDefinition,如下:
rest:比如/admins/user/**=rest[user],根據請求的方法,相當于/admins/user/**=perms[user:method] ,其中method為post,get,delete等。
port:比如/admins/user/**=port[8081],當請求的url的端口不是8081是跳轉到schemal://serverName:8081?queryString,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置里port的端口,queryString是你訪問的url里的?后面的參數。
perms:比如/admins/user/**=perms[user:add:*],perms參數可以寫多個,多個時必須加上引號,并且參數之間用逗號分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],當有多個參數時必須每個參數都通過才通過,想當于isPermitedAll()方法。
roles:比如/admins/user/**=roles[admin],參數可以寫多個,多個時必須加上引號,并且參數之間用逗號分割,當有多個參數時,比如/admins/user/**=roles["admin,guest"],每個參數通過才算通過,相當于hasAllRoles()方法。
anon:比如/admins/**=anon 沒有參數,表示可以匿名使用。
authc:比如/admins/user/**=authc表示需要認證才能使用,沒有參數
authcBasic:比如/admins/user/**=authcBasic沒有參數表示httpBasic認證
ssl:比如/admins/user/**=ssl沒有參數,表示安全的url請求,協議為https
user:比如/admins/user/**=user沒有參數表示必須存在用戶,當登入操作時不做檢查
一般情況下,我們可以將模塊作為一個授權單位,例如:
/blog!**.html = user
偶爾也會有將每一個URL作為一個授權單位進行控制,例如:
/blog!doAddNewArticle.html = authc,perms[addArticle]
但是URL的數量讓人頭疼,也許可以每開發一個功能的時候打開XML文件寫入URL然后同步到SVN,或者我們也可以找一個人專門做這些事情,無論是添加、刪除功能還是修改方法名都通知這個人去做...換位思考一下,我不希望我是這個人...
所以我要把這些URL放在數據庫進行管理。我要把他們統統Query出來放到filterChainDefinitions里。
我需要裝配一個Bean,實際上他是一個org.springframework.beans.factory.FactoryBean<Section>的實現。
<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>并實現需要Override的method,關鍵是getObject這個method:
private String filterChainDefinitions;
@Override
public Section getObject() throws Exception {
Ini ini = new Ini();
ini.load(filterChainDefinitions); //先載入XML中定義好的chain
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
/*
* 省略讀取步驟
* 繼續加入數據庫中的chain
* section.put("/**", "authc, roles[admin]");
*/
return section;
}
等等,這些僅僅是定義了權限。
我們需要在用戶訪問這些URL的時候去驗證一下用戶是否具備當前URL權限。
所以我定義了(事實上我們必須定義一個Realm,ShiroFilterFactoryBean需要SecurityManager,而我們使用的SecurityManager的實現類DefaultWebSecurityManager則需要一個Realm!):
<bean id="shiroDataBaseRealm" class="king.security.KingMainRealm">
并且Override了接口定義的method:
public class KingMainRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo( //授權
PrincipalCollection principals) {
UserBean _user = (UserBean) principals.fromRealm(getName()).iterator().next();
SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
/*
* 省略
*/
return authInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo( //認證
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,用戶登錄時doGetAuthorizationInfo會被調用,剩下的就是為每一個用戶管理這些權限了。
也許我們可以創建角色關聯多個權限,用戶關聯多個角色,類似這樣的設置不同的層次。
按你喜歡的方式去做吧