apache shiro集群实现(二)— cache共享
发布日期:2021-06-29 05:04:41 浏览次数:2 分类:技术文章

本文共 11188 字,大约阅读时间需要 37 分钟。

支持原创:

上一篇已经解决了第一个问题,session的共享,现在我们解决第二个问题cache的共享。

    先看下spring的配置文件,上一篇已经提到过了

[html] 
  1. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">  
  2.     <property name="sessionManager" ref="defaultWebSessionManager" />  
  3.     <property name="realm" ref="shiroDbRealm" />  
  4.     <property name="cacheManager" ref="memoryConstrainedCacheManager" />  
  5. </bean>  
  6. <bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />  
[html] 
  1. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">  
  2.     <property name="sessionManager" ref="defaultWebSessionManager" />  
  3.     <property name="realm" ref="shiroDbRealm" />  
  4.     <property name="cacheManager" ref="memoryConstrainedCacheManager" />  
  5. </bean>  
  6. <bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />  

    这里cacheManager我们注入了shiro自定的本机内存实现的cacheManager类,当然,这肯定不满足我们集群的需要,所以我们要自己实现cacheManager类,这里我还是用了redis作为cache的存储,先创建CustomShiroCacheManager实现类

[java] 
  1. public class CustomShiroCacheManager implements CacheManager, Destroyable {  
  2.   
  3.     private ShiroCacheManager shiroCacheManager;  
  4.   
  5.     public ShiroCacheManager getShiroCacheManager() {  
  6.         return shiroCacheManager;  
  7.     }  
  8.   
  9.     public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {  
  10.         this.shiroCacheManager = shiroCacheManager;  
  11.     }  
  12.   
  13.     @Override  
  14.     public <K, V> Cache<K, V> getCache(String name) throws CacheException {  
  15.         return getShiroCacheManager().getCache(name);  
  16.     }  
  17.   
  18.     @Override  
  19.     public void destroy() throws Exception {  
  20.         shiroCacheManager.destroy();  
  21.     }  
  22.   
  23. }  
[java] 
  1. public class CustomShiroCacheManager implements CacheManager, Destroyable {  
  2.   
  3.     private ShiroCacheManager shiroCacheManager;  
  4.   
  5.     public ShiroCacheManager getShiroCacheManager() {  
  6.         return shiroCacheManager;  
  7.     }  
  8.   
  9.     public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {  
  10.         this.shiroCacheManager = shiroCacheManager;  
  11.     }  
  12.   
  13.     @Override  
  14.     public <K, V> Cache<K, V> getCache(String name) throws CacheException {  
  15.         return getShiroCacheManager().getCache(name);  
  16.     }  
  17.   
  18.     @Override  
  19.     public void destroy() throws Exception {  
  20.         shiroCacheManager.destroy();  
  21.     }  
  22.   
  23. }  

这里为了扩展,引入了ShiroCacheManager接口

[java] 
  1. public interface ShiroCacheManager {  
  2.   
  3.     <K, V> Cache<K, V> getCache(String name);  
  4.   
  5.     void destroy();  
  6.   
  7. }  
[java] 
  1. public interface ShiroCacheManager {  
  2.   
  3.     <K, V> Cache<K, V> getCache(String name);  
  4.   
  5.     void destroy();  
  6.   
  7. }  
下面我们自己实现redis的cacheManger

[java] 
  1. public class JedisShiroCacheManager implements ShiroCacheManager {  
  2.   
  3.     @Autowired  
  4.     private JedisCacheManager jedisCacheManager;  
  5.   
  6.     @Override  
  7.     public <K, V> Cache<K, V> getCache(String name) {  
  8.         return new JedisShiroCache<K, V>(name, jedisCacheManager);  
  9.     }  
  10.   
  11.     @Override  
  12.     public void destroy() {  
  13.         jedisCacheManager.getJedis().shutdown();  
  14.     }  
  15.   
  16. }  
[java] 
  1. public class JedisShiroCacheManager implements ShiroCacheManager {  
  2.   
  3.     @Autowired  
  4.     private JedisCacheManager jedisCacheManager;  
  5.   
  6.     @Override  
  7.     public <K, V> Cache<K, V> getCache(String name) {  
  8.         return new JedisShiroCache<K, V>(name, jedisCacheManager);  
  9.     }  
  10.   
  11.     @Override  
  12.     public void destroy() {  
  13.         jedisCacheManager.getJedis().shutdown();  
  14.     }  
  15.   
  16. }  

当然,这里仅仅是getCache,我第一次看源码时,也有这样的疑问,cache的add、remove等等方法在哪里实现呢?我们继续看看shiro的源码就会知道答案了

这个是自己relm的AuthorizingRealm中的方法

[java] 
  1. protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {  
  2.   
  3.         if (principals == null) {  
  4.             return null;  
  5.         }  
  6.   
  7.         AuthorizationInfo info = null;  
  8.   
  9.         if (log.isTraceEnabled()) {  
  10.             log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");  
  11.         }  
  12.   
  13.         Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();  
  14.         if (cache != null) {  
  15.             if (log.isTraceEnabled()) {  
  16.                 log.trace("Attempting to retrieve the AuthorizationInfo from cache.");  
  17.             }  
  18.             Object key = getAuthorizationCacheKey(principals);  
  19.             info = cache.get(key);  
  20.             if (log.isTraceEnabled()) {  
  21.                 if (info == null) {  
  22.                     log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");  
  23.                 } else {  
  24.                     log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");  
  25.                 }  
  26.             }  
  27.         }  
  28.         if (info == null) {  
  29.             // Call template method if the info was not found in a cache   
  30.             info = <STRONG>doGetAuthorizationInfo</STRONG>(principals);  
  31.             // If the info is not null and the cache has been created, then cache the authorization info.  
  32.             if (info != null && cache != null) {  
  33.                 if (log.isTraceEnabled()) {  
  34.                     log.trace("Caching authorization info for principals: [" + principals + "].");  
  35.                 }  
  36.                 Object key = getAuthorizationCacheKey(principals);  
  37.                 <STRONG>cache.put</STRONG>(key, info);  
  38.             }  
  39.         }  
  40.         return info;  
  41.     }  
[java] 
  1. protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {  
  2.   
  3.         if (principals == null) {  
  4.             return null;  
  5.         }  
  6.   
  7.         AuthorizationInfo info = null;  
  8.   
  9.         if (log.isTraceEnabled()) {  
  10.             log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");  
  11.         }  
  12.   
  13.         Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();  
  14.         if (cache != null) {  
  15.             if (log.isTraceEnabled()) {  
  16.                 log.trace("Attempting to retrieve the AuthorizationInfo from cache.");  
  17.             }  
  18.             Object key = getAuthorizationCacheKey(principals);  
  19.             info = cache.get(key);  
  20.             if (log.isTraceEnabled()) {  
  21.                 if (info == null) {  
  22.                     log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");  
  23.                 } else {  
  24.                     log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");  
  25.                 }  
  26.             }  
  27.         }  
  28.         if (info == null) {  
  29.             // Call template method if the info was not found in a cache  
  30.             info = <strong>doGetAuthorizationInfo</strong>(principals);  
  31.             // If the info is not null and the cache has been created, then cache the authorization info.  
  32.             if (info != null && cache != null) {  
  33.                 if (log.isTraceEnabled()) {  
  34.                     log.trace("Caching authorization info for principals: [" + principals + "].");  
  35.                 }  
  36.                 Object key = getAuthorizationCacheKey(principals);  
  37.                 <strong>cache.put</strong>(key, info);  
  38.             }  
  39.         }  
  40.         return info;  
  41.     }  

如果大家去查查引入就知道我们自定义relm要实现一个叫做doGetAuthorizationInfo()的方法,它的作用是查询授权信息,我们注意加粗的2行,发现其实cache的put方法其实才是cache存储的核心类,其实现都在cache中,所以我们需要实现自己的cache,创建JedisShiroCache类

[java] 
  1. public class JedisShiroCache<K, V> implements Cache<K, V> {  
  2.   
  3.     private final String REDIS_SHIRO_CACHE = "shiro-cache:";  
  4.   
  5.     private JedisManager jedisManager;  
  6.   
  7.     private String name;  
  8.   
  9.     public JedisShiroCache(String name, JedisManager jedisManager) {  
  10.         this.name = name;  
  11.         this.jedisManager = jedisManager;  
  12.     }  
  13.       
  14.     /** 
  15.      * 自定义relm中的授权/认证的类名加上授权/认证英文名字 
  16.      * @return 
  17.      */  
  18.     public String getName() {  
  19.         if (name == null)  
  20.             return "";  
  21.         return name;  
  22.     }  
  23.   
  24.     public void setName(String name) {  
  25.         this.name = name;  
  26.     }  
  27.   
  28.     @Override  
  29.     public V get(K key) throws CacheException {  
  30.         byte[] byteKey = SerializeUtil.serialize(getCacheKey(key));  
  31.         byte[] byteValue = jedisManager.getValueByKey(byteKey);  
  32.         return (V) SerializeUtil.deserialize(byteValue);  
  33.     }  
  34.   
  35.     @Override  
  36.     public V put(K key, V value) throws CacheException {  
  37.         V previos = get(key);  
  38.         jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)),  
  39.                 SerializeUtil.serialize(value));  
  40.         return previos;  
  41.     }  
  42.   
  43.     @Override  
  44.     public V remove(K key) throws CacheException {  
  45.         V previos = get(key);  
  46.         jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key)));  
  47.         return previos;  
  48.     }  
  49.   
  50.     @Override  
  51.     public void clear() throws CacheException {  
  52.         byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE  
  53.                 + "*");  
  54.         jedisManager.deleteByKeysPattern(keysPattern);  
  55.     }  
  56.   
  57.     @Override  
  58.     public int size() {  
  59.         if (keys() == null)  
  60.             return 0;  
  61.         return keys().size();  
  62.     }  
  63.   
  64.     @Override  
  65.     public Set<K> keys() {  
  66.         Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil  
  67.                 .serialize(this.REDIS_SHIRO_CACHE + "*"));  
  68.         Set<K> keys = new HashSet<K>();  
  69.         for (byte[] bs : byteSet) {  
  70.             keys.add((K) SerializeUtil.deserialize(bs));  
  71.         }  
  72.         return keys;  
  73.     }  
  74.   
  75.     @Override  
  76.     public Collection<V> values() {  
  77.         Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil  
  78.                 .serialize(this.REDIS_SHIRO_CACHE + "*"));  
  79.         List<V> result = new LinkedList<V>();  
  80.         for (byte[] bs : byteSet) {  
  81.             result.add((V) SerializeUtil.deserialize(jedisManager  
  82.                     .getValueByKey(bs)));  
  83.         }  
  84.         return result;  
  85.     }  
  86.   
  87.     private String getCacheKey(Object key) {  
  88.         return this.REDIS_SHIRO_CACHE + getName() + ":" + key;  
  89.     }  
[java] 
  1. public class JedisShiroCache<K, V> implements Cache<K, V> {  
  2.   
  3.     private final String REDIS_SHIRO_CACHE = "shiro-cache:";  
  4.   
  5.     private JedisManager jedisManager;  
  6.   
  7.     private String name;  
  8.   
  9.     public JedisShiroCache(String name, JedisManager jedisManager) {  
  10.         this.name = name;  
  11.         this.jedisManager = jedisManager;  
  12.     }  
  13.       
  14.     /** 
  15.      * 自定义relm中的授权/认证的类名加上授权/认证英文名字 
  16.      * @return 
  17.      */  
  18.     public String getName() {  
  19.         if (name == null)  
  20.             return "";  
  21.         return name;  
  22.     }  
  23.   
  24.     public void setName(String name) {  
  25.         this.name = name;  
  26.     }  
  27.   
  28.     @Override  
  29.     public V get(K key) throws CacheException {  
  30.         byte[] byteKey = SerializeUtil.serialize(getCacheKey(key));  
  31.         byte[] byteValue = jedisManager.getValueByKey(byteKey);  
  32.         return (V) SerializeUtil.deserialize(byteValue);  
  33.     }  
  34.   
  35.     @Override  
  36.     public V put(K key, V value) throws CacheException {  
  37.         V previos = get(key);  
  38.         jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)),  
  39.                 SerializeUtil.serialize(value));  
  40.         return previos;  
  41.     }  
  42.   
  43.     @Override  
  44.     public V remove(K key) throws CacheException {  
  45.         V previos = get(key);  
  46.         jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key)));  
  47.         return previos;  
  48.     }  
  49.   
  50.     @Override  
  51.     public void clear() throws CacheException {  
  52.         byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE  
  53.                 + "*");  
  54.         jedisManager.deleteByKeysPattern(keysPattern);  
  55.     }  
  56.   
  57.     @Override  
  58.     public int size() {  
  59.         if (keys() == null)  
  60.             return 0;  
  61.         return keys().size();  
  62.     }  
  63.   
  64.     @Override  
  65.     public Set<K> keys() {  
  66.         Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil  
  67.                 .serialize(this.REDIS_SHIRO_CACHE + "*"));  
  68.         Set<K> keys = new HashSet<K>();  
  69.         for (byte[] bs : byteSet) {  
  70.             keys.add((K) SerializeUtil.deserialize(bs));  
  71.         }  
  72.         return keys;  
  73.     }  
  74.   
  75.     @Override  
  76.     public Collection<V> values() {  
  77.         Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil  
  78.                 .serialize(this.REDIS_SHIRO_CACHE + "*"));  
  79.         List<V> result = new LinkedList<V>();  
  80.         for (byte[] bs : byteSet) {  
  81.             result.add((V) SerializeUtil.deserialize(jedisManager  
  82.                     .getValueByKey(bs)));  
  83.         }  
  84.         return result;  
  85.     }  
  86.   
  87.     private String getCacheKey(Object key) {  
  88.         return this.REDIS_SHIRO_CACHE + getName() + ":" + key;  
  89.     }  

最后修改spring配置文件

[html] 
  1. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">  
  2.     <property name="sessionManager" ref="defaultWebSessionManager" />  
  3.     <property name="realm" ref="shiroDbRealm" />  
  4.     <property name="cacheManager" ref="customShiroCacheManager" />  
  5. </bean>  
  6. <bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager">  
  7.     <property name="shiroCacheManager" ref="jedisShiroCacheManager" />  
  8. </bean>  
  9.       
  10. <bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />  
[html] 
  1. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">  
  2.     <property name="sessionManager" ref="defaultWebSessionManager" />  
  3.     <property name="realm" ref="shiroDbRealm" />  
  4.     <property name="cacheManager" ref="customShiroCacheManager" />  
  5. </bean>  
  6. <bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager">  
  7.     <property name="shiroCacheManager" ref="jedisShiroCacheManager" />  
  8. </bean>  
  9.       
  10. <bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />  

这样就完成了整个shiro集群的配置

转载地址:https://blog.csdn.net/zhaokuner/article/details/14004087 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Apache-Shiro+Zookeeper系统集群安全解决方案之会话管理
下一篇:apache shiro集群实现(一) session共享

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月09日 00时58分55秒