apache shiro叢集實現(二)— cache共用

來源:互聯網
上載者:User

    上一篇已經解決了第一個問題,session的共用,現在我們解決第二個問題cache的共用。

    先看下spring的設定檔,上一篇已經提到過了

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository"><property name="sessionManager" ref="defaultWebSessionManager" /><property name="realm" ref="shiroDbRealm" /><property name="cacheManager" ref="memoryConstrainedCacheManager" /></bean><bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />

    這裡cacheManager我們注入了shiro自定的本機記憶體實現的cacheManager類,當然,這肯定不滿足我們叢集的需要,所以我們要自己實現cacheManager類,這裡我還是用了redis作為cache的儲存,先建立CustomShiroCacheManager實作類別

public class CustomShiroCacheManager implements CacheManager, Destroyable {private ShiroCacheManager shiroCacheManager;public ShiroCacheManager getShiroCacheManager() {return shiroCacheManager;}public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {this.shiroCacheManager = shiroCacheManager;}@Overridepublic <K, V> Cache<K, V> getCache(String name) throws CacheException {return getShiroCacheManager().getCache(name);}@Overridepublic void destroy() throws Exception {shiroCacheManager.destroy();}}

這裡為了擴充,引入了ShiroCacheManager介面

public interface ShiroCacheManager {<K, V> Cache<K, V> getCache(String name);void destroy();}
下面我們自己實現redis的cacheManger
public class JedisShiroCacheManager implements ShiroCacheManager {@Autowiredprivate JedisCacheManager jedisCacheManager;@Overridepublic <K, V> Cache<K, V> getCache(String name) {return new JedisShiroCache<K, V>(name, jedisCacheManager);}@Overridepublic void destroy() {jedisCacheManager.getJedis().shutdown();}}

當然,這裡僅僅是getCache,我第一次看源碼時,也有這樣的疑問,cache的add、remove等等方法在哪裡實現呢。我們繼續看看shiro的源碼就會知道答案了

這個是自己relm的AuthorizingRealm中的方法

protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {        if (principals == null) {            return null;        }        AuthorizationInfo info = null;        if (log.isTraceEnabled()) {            log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");        }        Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();        if (cache != null) {            if (log.isTraceEnabled()) {                log.trace("Attempting to retrieve the AuthorizationInfo from cache.");            }            Object key = getAuthorizationCacheKey(principals);            info = cache.get(key);            if (log.isTraceEnabled()) {                if (info == null) {                    log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");                } else {                    log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");                }            }        }        if (info == null) {            // Call template method if the info was not found in a cache            info = <strong>doGetAuthorizationInfo</strong>(principals);            // If the info is not null and the cache has been created, then cache the authorization info.            if (info != null && cache != null) {                if (log.isTraceEnabled()) {                    log.trace("Caching authorization info for principals: [" + principals + "].");                }                Object key = getAuthorizationCacheKey(principals);                <strong>cache.put</strong>(key, info);            }        }        return info;    }

如果大家去查查引入就知道我們自訂relm要實現一個叫做doGetAuthorizationInfo()的方法,它的作用是查詢授權資訊,我們注意加粗的2行,發現其實cache的put方法其實才是cache儲存的核心類,其實現都在cache中,所以我們需要實現自己的cache,建立JedisShiroCache類

public class JedisShiroCache<K, V> implements Cache<K, V> {private final String REDIS_SHIRO_CACHE = "shiro-cache:";private JedisManager jedisManager;private String name;public JedisShiroCache(String name, JedisManager jedisManager) {this.name = name;this.jedisManager = jedisManager;}/** * 自訂relm中的授權/認證的類名加上授權/認證英文名字 * @return */public String getName() {if (name == null)return "";return name;}public void setName(String name) {this.name = name;}@Overridepublic V get(K key) throws CacheException {byte[] byteKey = SerializeUtil.serialize(getCacheKey(key));byte[] byteValue = jedisManager.getValueByKey(byteKey);return (V) SerializeUtil.deserialize(byteValue);}@Overridepublic V put(K key, V value) throws CacheException {V previos = get(key);jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)),SerializeUtil.serialize(value));return previos;}@Overridepublic V remove(K key) throws CacheException {V previos = get(key);jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key)));return previos;}@Overridepublic void clear() throws CacheException {byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE+ "*");jedisManager.deleteByKeysPattern(keysPattern);}@Overridepublic int size() {if (keys() == null)return 0;return keys().size();}@Overridepublic Set<K> keys() {Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil.serialize(this.REDIS_SHIRO_CACHE + "*"));Set<K> keys = new HashSet<K>();for (byte[] bs : byteSet) {keys.add((K) SerializeUtil.deserialize(bs));}return keys;}@Overridepublic Collection<V> values() {Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil.serialize(this.REDIS_SHIRO_CACHE + "*"));List<V> result = new LinkedList<V>();for (byte[] bs : byteSet) {result.add((V) SerializeUtil.deserialize(jedisManager.getValueByKey(bs)));}return result;}private String getCacheKey(Object key) {return this.REDIS_SHIRO_CACHE + getName() + ":" + key;}

最後修改spring設定檔

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository"> <property name="sessionManager" ref="defaultWebSessionManager" /><property name="realm" ref="shiroDbRealm" /><property name="cacheManager" ref="customShiroCacheManager" /></bean><bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager"><property name="shiroCacheManager" ref="jedisShiroCacheManager" /></bean><bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />

這樣就完成了整個shiro叢集的配置

源碼地址:https://github.com/michaelliuyang/shiro-redis-cluster


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.