第十章:Shiro的Cache——深入淺出學Shiro細粒度許可權開發框架
概述
Shiro開發團隊明白在許多應用程式中效能是至關重要的。Caching 是Shiro 中的一個重要功能,以確保安全操作保持儘可能的快。
但是,Shiro並不實現快取的功能,Shiro 的快取支援基本上是一個抽象的(包裝)API,它將“坐”在一個基本的快取機制產品(例如,Ehcache,OSCache,Terracotta,Coherence,GigaSpaces,JBossCache 等)之上。這允許Shiro終端使用者配置他們喜歡的任何快取機制。
Caching API
Shiro 有三個重要的快取介面:
1:CacheManager - 負責所有快取的主要管理元件,它返回Cache 例項
2:Cache - 維護key/value 對
3:CacheManagerAware - 通過想要接收和使用CacheManager 例項的元件來實現
CacheManager 返回Cache 例項,各種不同的Shiro 元件使用這些Cache 例項來快取必要的資料。任何實現了CacheManagerAware 的Shiro 元件將會自動地接收一個配置好的CacheManager,該CacheManager 能夠用來獲取Cache 例項。
Shiro 的SecurityManager 實現及所有AuthorizingRealm實現都實現了CacheManagerAware
Shiro 提供了一個個立即可用的EhCacheManager 實現
Caching 配置
n通過在SecurityManager上設定了CacheManger,它反過來也會將它設定到實現了CacheManagerAware 的各種不同的Realm 上,示例如下:
cacheManager = org.apache.shiro.cache.ehcache.EhcacheManager
securityManager.cacheManager = $cacheManager
預設的EHCache使用一個Shiro特定的ehcache.xml檔案來配置,大致內容如下:
<cache name="shiro-activeSessionCache" maxElementsInMemory="10000" overflowToDisk="true" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0" diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/>
包裝使用其他的Cache框架
可以通過寫一個類來實現Shiro的CacheManager,在這個類裡面包裝使用任何你想要使用的Cache框架,這裡以使用Srping的快取框架為例,參考如下:
public class MyCacheManager implements CacheManager {
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
org.springframework.cache.Cache springCache = cacheManager.getCache(name);
return new SpringCacheWrapper(springCache);
}
class SpringCacheWrapper implements Cache {
private org.springframework.cache.Cache springCache;
SpringCacheWrapper(org.springframework.cache.Cache springCache) {
this.springCache = springCache;
}
public Object get(Object key) throws CacheException {
Object value = springCache.get(key);
if (value instanceof SimpleValueWrapper) {
return ((SimpleValueWrapper) value).get();
}
return value;
}
//等等,還有幾個需要實現的方法,都可以使用你要使用的快取框架去實現
}
}
快取資料同步更新的解決方案
使用Shiro的時候,快取資料最大的問題就在於資料同步更新。
因為Shiro只負責驗證部分,如果應用程式修改了人員的許可權,那麼就需要同步更新到Shiro裡面去,也就是要同步Shiro的快取資料。
一個解決方案就是完全廢棄Shiro的快取機制,自己在應用中控制資料的快取
這裡給出另一種簡易可行的方案:
1:如果你使用的Spring,而且是自定義的Realm,那麼可以在你的Realm裡面新增一個方法來刪除該使用者的快取資料,這樣下次shiro在驗證這個使用者的時候,就會重新去獲取資料,從而實現資料的同步
2:由於是自定義的Realm,可以把該物件作為Spring的bean,注入到你的業務物件中,在需要的時候就可以呼叫該方法來刪除shiro的快取資料了
示例,比如在前面自定義的MyRealm中,新增如下方法,示例如下:
public void removeUserCache(String userId){
SimplePrincipalCollection pc = new SimplePrincipalCollection();
pc.add(userId, super.getName());
super.clearCachedAuthorizationInfo(pc);
}
然後在HelloAnno中進行測試,示例如下:
1:要注入MyRealm,但注意需要使用getter/setter來注入
2:在main方法中,示例如下:
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloAnno t = (HelloAnno)ctx.getBean("helloAnno");
t.login();
t.t();
t.t();
t.getMr().removeUserCache("javass");
t.t();
}