1. 程式人生 > 其它 >第十章:Shiro的Cache——深入淺出學Shiro細粒度許可權開發框架

第十章: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();
  }