SpringMVC+MyBatis - 5 Security-Shiro-01
安全認證框架-APACHE SHIRO研究心得
最近因為項目需要,研究了一下Apache Shiro安全認證框架,把心得記錄下來。(原創(chuàng)by:西風吹雨)當然,如果認證信息來自于多方面,多個不同的來源(比如來自兩個庫中,或者一個數據庫,一個是ldap,再配上一個缺省的基于文本的測試用等等),我們可以為securityManager指定realms參數,即把這一組安全配置都配置上。各個具體的realm實現提供了方法來獲取用戶基本信息、角色、權限等。
3、緩存
如果項目中已經存在使用的ehCacheManager配置(org.springframework.cache.ehcache.EhCacheManagerFactoryBea
同時,也可以設置cacheManagerConfigFile參數來指定ehCache的配置文件。






































當我們把securityManager的sessionMode參數設置為native時,那么shrio就將用戶的基本認證信息保存到缺省名稱為shiro-activeSessionCache 的Cache中
org.apache.shiro.web.mgt.DefaultWebSecurityManage
如果系統(tǒng)內的用戶數特別多,我們需要使用CacheSessionDao來基于Cache進行操作,因此,這里需要顯示配置一個sessionManager(org.apache.shiro.web.session.mgt.DefaultWebSessionManager
配置CacheSessionDao時,我們可以指定屬性activeSessionsCacheName的名稱來替換掉缺省名 shiro-activeSessionCache。我們再把該sessionManager配置給DefaultWebSecurityManage


































































































































5、基于url資源的權限管理
我們可以簡單配置在shiroFilter的filterChainDefinitions中,也可以考慮通過一個文本文件,我們讀入內容后設置進去。或者通過Ini類來裝入Ini文件內容,到時取出urls的部分來設置給shiroFilter的filterChainDefinitions。也可以把這部分數據存入數據庫表中,到時讀出一個Map來設置給shiroFilter的filterChainDefinitionsMa
每次保存時,系統(tǒng)把SimpleCookie的信息設置好之后,先用DefaultSerializer把其用jvm缺省序列化方式序列化成byte[],然后再用cipherService(缺省是aes加密算法)來加密該byte[],最后用Base64.encodeToString(serialized)壓縮成一個字符串,再寫入名稱為rememberMe的Cookie中。
在Spring配置中,配置好RememberMeManager,裝配上sericerlizer和cipherService(根據實際情況選用適當的加密算法),最后把rememberMeManager設置給DefaultWebSecurityManage
【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是協(xié)議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請求,協(xié)議為https
user:比如/admins/user/**=user沒有參數表示必須存在用戶,當登入操作時不做檢查
一般情況下,我們可以將模塊作為一個授權單位,例如:
/blog!**.html = user
偶爾也會有將每一個URL作為一個授權單位進行控制,例如:
/blog!doAddNewArticle.html = authc,perms[addArticle]
但是URL的數量讓人頭疼,也許可以每開發(fā)一個功能的時候打開XML文件寫入URL然后同步到SVN,或者我們也可以找一個人專門做這些事情,無論是添加、刪除功能還是修改方法名都通知這個人去做...換位思考一下,我不希望我是這個人...
所以我要把這些URL放在數據庫進行管理。我要把他們統(tǒng)統(tǒng)Query出來放到filterChainDefinitions里。
我需要裝配一個Bean,實際上他是一個org.springframework.beans.factory.FactoryBean<Section>的實現。
<property name="filterChainDefinitions">
/404.htm = anon
/main!main.html = anon
</property>
</bean>
然后將其注入:
<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:
@Override
public Section getObject() throws Exception {
Ini ini = new Ini();
ini.load(filterChainDefinitions); //先載入XML中定義好的chain
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
/*
* 省略讀取步驟
* 繼續(xù)加入數據庫中的chain
* section.put("/**", "authc, roles[admin]");
*/
return section;
}
等等,這些僅僅是定義了權限。
我們需要在用戶訪問這些URL的時候去驗證一下用戶是否具備當前URL權限。
所以我定義了(事實上我們必須定義一個Realm,ShiroFilterFactoryBean需要SecurityManager,而我們使用的SecurityManager的實現類DefaultWebSecurityManager則需要一個Realm!):
并且Override了接口定義的method:
@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會被調用,剩下的就是為每一個用戶管理這些權限了。
也許我們可以創(chuàng)建角色關聯(lián)多個權限,用戶關聯(lián)多個角色,類似這樣的設置不同的層次。
按你喜歡的方式去做吧
posted on 2014-07-11 09:38 crazycy 閱讀(2262) 評論(0) 編輯 收藏 所屬分類: JavaEE技術