shiro+redis+springMvc整合配置及说明

技术背景:shiro安全框架,redis作缓存,再整合spring。

1、配置web.xml

  1. <filter>  
  2.     <filter-name>ShiroFilter</filter-name>  
  3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  4. </filter>  
  5.   
  6. <filter-mapping>  
  7.     <filter-name>ShiroFilter</filter-name>  
  8.     <url-pattern>/*</url-pattern>  
  9. </filter-mapping>  
2、配置spring-shiro.xml的配置文件
  1.     <!--shiro配置-->   
  2.     <!--securityManager是shiro核心部分-->  
  3.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
  4.          <property name="sessionManager" ref="webSessionManager" />  
  5.          <property name="realm" ref="restfulAuthRealm"/>  
  6.          <property name="rememberMeManager.cookie.name" value="rememberMe"/>  
  7.          <property name="rememberMeManager.cookie.maxAge" value="${rememberMeManager.cookie.maxAge}"/>  
  8.     </bean>  
  9.     <!--配置shiro的sessionManager-->  
  10.     <bean id="webSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">  
  11.          <property name="sessionDAO" ref="redisSessionDAO"></property>  
  12.     </bean>  
  13.     <!--权限操作bean-->  
  14.     <bean id="permissionManager" class="com.securityframework.local.PermissionManagerLocalImpl" />  
  15.     <!--账号操作bean-->  
  16.     <bean id="accountManagerImpl" class="com.securityframework.local.AccountManagerLocalImpl"/>  
  17.     <!--自定义realm-->  
  18.     <bean id ="restfulAuthRealm" class="com.isoftstone.securityframework.restful.client.web.shiro.realm.RestAuthRealm">  
  19.         <property name="accountManagerImpl" ref="accountManagerImpl"></property>  
  20.         <property name="permissionManagerImpl" ref="permissionManager"></property>  
  21.         <property name="cacheManager" ref="redisCacheManager"></property>  
  22.             <property name="platformLabel">  
  23.          <value>${platformLabel}</value>  
  24.         </property>  
  25.      </bean>       
  26.      <!--动态获取filterchaindefinitions,此处与下面ShiroFilter bean所引用的类对应-->  
  27.      <bean id="systemUrlChainManager" class="com.securityframework.restful.client.web.shiro.mgt.RestUrlChainManager">  
  28.           <property name="permissionManager" ref="permissionManager"></property>  
  29.          <property name="platformLabel">  
  30.              <value>${platformLabel}</value>  
  31.          </property>  
  32.         <property name="systemLabel">  
  33.             <value>${systemLabel}</value>  
  34.         </property>  
  35.       </bean>  
  36.       <!--与web.xml中配置的filter同名,它对应的类原本是<code class="xml string">org.apache.shiro.spring.web.ShiroFilterFactoryBean,</code>-->  
  37.       <!--这里为了动态获取filterchaindefinitions改写了<code class="xml string">ShiroFilterFactoryBean类,它们的作用是一样的</code>-->   
  38.       <bean id="ShiroFilter" class="com.securityframework.restful.client.web.shiro.filter.RestAuthShiroFilter">  
  39.         <property name="urlChainManager" ref="systemUrlChainManager" />  
  40.         <property name="securityManager" ref="securityManager"/>  
  41.         <property name="loginUrl" value="../../res/user/login.html"/>  
  42.         <property name="unauthorizedUrl" value="/html/413.html"/>  
  43.         <property name="filters">  
  44.             <util:map>  
  45.                 <entry key="authc">  
  46.                     <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>  
  47.                 </entry>  
  48.             </util:map>  
  49.         </property>                        
  50.         <property name="filterChainDefinitions">  
  51.             <value>  
  52.                 /images/** =anon  
  53.                 /help/** =anon  
  54.                 /css/** = anon  
  55.                 /easyui/** =anon  
  56.                 /javascript/** =anon  
  57.                 /commons/** =anon  
  58.                 /jsplugin/** =anon  
  59.                 /ueditor/** =anon  
  60.                 /html/** =anon                
  61.                 /index.html = anon  
  62.                 / = anon  
  63.                 /** = user  
  64.             </value>  
  65.          </property>  
  66.     </bean>  
  67. <span><span class="comments">    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --></span><span></span></span>  
  68. <pre name="code" class="java">    <bean id="lifecycleBeanPostProcessor"   class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>   
  69.        
  70.      <!--redis配置-->  
<!-- basic jedis pool configuration -->
    <bean id="basicPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis.pool.maxActive}" />  
        <property name="maxIdle" value="${redis.pool.maxIdle}" />  
        <property name="maxWait" value="${redis.pool.maxWaitTime}" />  
        <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />  
    </bean>
    <!-- JedisPool  configuration-->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">  
        <constructor-arg index="0" ref="basicPoolConfig" />  
        <constructor-arg index="1" value="${redis.host.ip}" />  
        <constructor-arg index="2" value="${redis.host.port}" />  
    </bean>  
    <!-- JedisPool manager -->
    <bean id="jedisPoolManager" class="com.isoftstone.securityframework.support.redis.JedisPoolManager">
        <property name="jedisPool" ref="jedisPool"></property>
    </bean>
    <!--redisCacheManager要实现org.apache.shiro.cache.CacheManager接口,让shiro使用redis的缓存-->
    <bean id="redisCacheManager" class="com.securityframework.support.redis.RedisCacheManager">
        <property name="redisManager" ref="jedisPoolManager"></property>
    </bean>
    <!-- Redis session dao -->
<!--redisSessionDAO继承实现了org.apache.shiro.session.mgt.eis.SessionDAO的AbstractSessionDAO-->
    <bean id="redisSessionDAO" class="com.securityframework.support.redis.RedisSessionDAO">
        <property name="redisManager" ref="jedisPoolManager"></property>
        <property name="expire" value="${shiro.session.timeout}"></property>
    </bean>
3、上述bean对应的类(我们自己重写的)
  • com.securityframework.local.PermissionManagerLocalImpl
  • com.securityframework.local.AccountManagerLocalImpl
  • com.securityframework.restful.client.web.shiro.realm.RestAuthRealm
  • com.securityframework.restful.client.web.shiro.mgt.RestUrlChainManager
  • com.securityframework.restful.client.web.shiro.filter.RestAuthShiroFilter
  • com.securityframework.support.redis.JedisPoolManager
  • com.securityframework.support.redis.RedisCacheManager
  • com.securityframework.support.redis.RedisSessionDAO

     (1)com.securityframework.local.PermissionManagerLocalImpl

         对权限信息的增删改查

     (2)com.securityframework.local.AccountManagerLocalImpl

         对账号信息的增删改查

     (3)com.securityframework.restful.client.web.shiro.realm.RestAuthRealm

         在shiro学习和使用实例(2)——登陆认证和授权有详细解释

     (4)com.securityframework.restful.client.web.shiro.mgt.RestUrlChainManager        

  1. public class RestUrlChainManager {  
  2.     PermissionManager permissionManager;   
  3.       
  4.     private String platformLabel ;  
  5.       
  6.     private String systemLabel;  
  7.       
  8.     public Map<String,String> buildChainMap(){  
  9.           
  10.         Map<String,String> p = new HashMap<String,String>();  
  11.         //获取权限信息,以便获得每个权限下面的资源  
  12.         List<com.isoftstone.securityframework.api.Permission> perms = permissionManager.findSubsystemPermission(platformLabel, systemLabel);  
  13.           
  14.         if(null != perms && perms.size() > 0){  
  15.             System.out.println(" SystemUrlChainManager.buildChainMap----- STATUS_OK -----");  
  16.         }  
  17.         if (null != perms){  
  18.             String value ;  
  19.             for (int i = 0; i < perms.size(); i++) {  
  20.                 value = "";  
  21.                 com.isoftstone.securityframework.api.Permission perm = perms.get(i);  
  22.                 if(i == 0){  
  23.                     value = "authc," + perm.getPermissionName();  
  24.                 }else{  
  25.                     value = perm.getPermissionName();  
  26.                 }  
  27.                 List<com.isoftstone.securityframework.api.Resource> resources = perm.getResources();  
  28.                   
  29.                 if(null != resources){  
  30.                     for (int j = 0; j < resources.size(); j++) {  
  31.                         com.isoftstone.securityframework.api.Resource resource = resources.get(j);  
  32.                                                 //格式{'mvc/web/usermgt/add.json','perms[com.securitycenter.user:ADD]'},它  
  33.                                                 //对应spring-shiro.xml配置文件中ShiroFilter bean下的filterChainDefinitions  
  34.                                                 p.put(resource.getRes(), String.format("perms[%s]", value));  
  35.                     }  
  36.                 }  
  37.             }  
  38.         }  
  39.         return p;  
  40.     }  
  41.   
  42.         /** 
  43.          *  setter和getter方法省略 
  44.          **/  
  45.  }  
      RestUrlChainManager类中的buildChainMap方法是从数据库获取资源,组成动态的filterChainDefinitions,以便系统对所有的资源请求的拦截都可以动态可配置

     (5)com.securityframework.restful.client.web.shiro.filter.RestAuthShiroFilter

  1. public Map<String,String> getChainFilterMap(){  
  2.         return getUrlChainManager().buildChainMap();  
  3.     }  
  4. public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {  
  5.         Map<String, String> allFilterChainDefinitionMap = getFilterChainDefinitionMap();  
  6.         if (CollectionUtils.isEmpty(allFilterChainDefinitionMap)){  
  7.             this.filterChainDefinitionMap = filterChainDefinitionMap;  
  8.         }else{  
  9.             //add custom chain definition  
  10.             allFilterChainDefinitionMap.putAll(filterChainDefinitionMap);  
  11.         }  
  12.                   
  13.     }  
  14. public void setFilterChainDefinitions(String definitions) {  
  15.         Ini ini = new Ini();  
  16.         ini.load(definitions);  
  17.         //did they explicitly state a 'urls' section?  Not necessary, but just in case:  
  18.         Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);  
  19.         if (CollectionUtils.isEmpty(section)) {  
  20.             //no urls section.  Since this _is_ a urls chain definition property, just assume the  
  21.             //default section contains only the definitions:  
  22.             section = ini.getSection(Ini.DEFAULT_SECTION_NAME);  
  23.         }  
  24.         setFilterChainDefinitionMap(section);  
  25.           
  26.         //add custom path filter map   
  27.         try{  
  28.             Map<String,String> permFilterMap = this.getChainFilterMap();  
  29.             if(!CollectionUtils.isEmpty(permFilterMap)){  
  30.                 setFilterChainDefinitionMap(permFilterMap);  
  31.             }  
  32.         }catch(Exception ex){  
  33.             log.error("Load custom path filters to shiro filter failure.");  
  34.             ex.printStackTrace();  
  35.         }  
  36.           
  37.     }  
      RestAuthShiroFilter其实就是使用的 org.apache.shiro.spring.web.ShiroFilterFactoryBean,里面的方法完全一样,只是为了动态获取filterChainDefinitions在 ShiroFilterFactoryBean类的基础上,增改了上述三个方法。实现的目的就是将RestUrlChainManager组装的{资源,权限}map加入到filterChainDefinitions中,实现拦截。从而能够动态的维护shiro拦截器拦截的内容。

     (6)com.securityframework.support.redis.JedisPoolManager

  1. /** 
  2.  * JedisPool 管理类  
  3.  * 用于单个redis 集群, 每个redis集群由master-salve组成 
  4.  */  
  5. public class JedisPoolManager {  
  6.   
  7.     private static Log log = LogFactory.getLog(JedisPoolManager.class);  
  8.   
  9.     private JedisPool jedisPool;  
  10.     /** 
  11.      * redis的List集合 ,向key这个list添加元素 
  12.      */  
  13.     public long rpush(String key, String string) {  
  14.         Jedis jedis = null;  
  15.         try {  
  16.             jedis = jedisPool.getResource();  
  17.             long ret = jedis.rpush(key, string);  
  18.             jedisPool.returnResource(jedis);  
  19.             return ret;  
  20.         } catch (Exception e) {  
  21.             log.error(e);  
  22.             if (jedis != null) {  
  23.                 jedisPool.returnBrokenResource(jedis);  
  24.             }  
  25.             throw new JedisException(e);  
  26.         }  
  27.     }  
  28.     /** 
  29.      * 获取key这个List,从第几个元素到第几个元素 LRANGE key start 
  30.      * stop返回列表key中指定区间内的元素,区间以偏移量start和stop指定。 
  31.      * 下标(index)参数start和stop都以0为底,也就是说,以0表示列表的第一个元素,以1表示列表的第二个元素,以此类推。 
  32.      * 也可以使用负数下标,以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。 
  33.      */  
  34.     public List<String> lrange(String key, long start, long end) {  
  35.         Jedis jedis = null;  
  36.         try {  
  37.             jedis = jedisPool.getResource();  
  38.             List<String> ret = jedis.lrange(key, start, end);  
  39.             jedisPool.returnResource(jedis);  
  40.             return ret;  
  41.         } catch (Exception e) {  
  42.             log.error(e);  
  43.             if (jedis != null) {  
  44.                 jedisPool.returnBrokenResource(jedis);  
  45.             }  
  46.             throw new JedisException(e);  
  47.         }  
  48.     }  
  49.     /** 
  50.      * 将哈希表key中的域field的值设为value。 
  51.      */  
  52.     public void hset(String key, String field, String value) {  
  53.         Jedis jedis = null;  
  54.         try {  
  55.             jedis = jedisPool.getResource();  
  56.             jedis.hset(key, field, value);  
  57.             jedisPool.returnResource(jedis);  
  58.         } catch (Exception e) {  
  59.             log.error(e);  
  60.             if (jedis != null) {  
  61.                 jedisPool.returnBrokenResource(jedis);  
  62.             }  
  63.             throw new JedisException(e);  
  64.         }  
  65.     }  
  66.     /** 
  67.      * 向key赋值 
  68.      */  
  69.     public void set(String key, String value) {  
  70.         Jedis jedis = null;  
  71.         try {  
  72.             jedis = jedisPool.getResource();  
  73.             jedis.set(key, value);  
  74.             jedisPool.returnResource(jedis);  
  75.         } catch (Exception e) {  
  76.             log.error(e);  
  77.             if (jedis != null) {  
  78.                 jedisPool.returnBrokenResource(jedis);  
  79.             }  
  80.             throw new JedisException(e);  
  81.         }  
  82.     }  
  83.     /** 
  84.      * 向key赋值 
  85.      */  
  86.     public void set(byte[] key, byte[] value) {  
  87.         Jedis jedis = null;  
  88.         try {  
  89.             jedis = jedisPool.getResource();  
  90.             jedis.set(key, value);  
  91.             jedisPool.returnResource(jedis);  
  92.         } catch (Exception e) {  
  93.             log.error(e);  
  94.             if (jedis != null) {  
  95.                 jedisPool.returnBrokenResource(jedis);  
  96.             }  
  97.             throw new JedisException(e);  
  98.         }  
  99.     }  
  100.     /** 
  101.      * 获取key的值 
  102.      */  
  103.     public String get(String key) {  
  104.         Jedis jedis = null;  
  105.         try {  
  106.             jedis = jedisPool.getResource();  
  107.             String value = jedis.get(key);  
  108.             jedisPool.returnResource(jedis);  
  109.             return value;  
  110.         } catch (Exception e) {  
  111.             log.error(e);  
  112.             if (jedis != null) {  
  113.                 jedisPool.returnBrokenResource(jedis);  
  114.             }  
  115.             throw new JedisException(e);  
  116.         }  
  117.     }  
  118.     /** 
  119.      * 获取key的值 
  120.      */  
  121.     public byte[] get(byte[] key) {  
  122.         Jedis jedis = null;  
  123.         try {  
  124.             jedis = jedisPool.getResource();  
  125.             byte[] value = jedis.get(key);  
  126.             jedisPool.returnResource(jedis);  
  127.             return value;  
  128.         } catch (Exception e) {  
  129.             log.error(e);  
  130.             if (jedis != null) {  
  131.                 jedisPool.returnBrokenResource(jedis);  
  132.             }  
  133.             throw new JedisException(e);  
  134.         }  
  135.   
  136.     }  
  137.     /** 
  138.      * 将多个field - value(域-值)对设置到哈希表key中。 
  139.      */  
  140.     public void hmset(String key, Map<String, String> map) {  
  141.         Jedis jedis = null;  
  142.         try {  
  143.              jedis = jedisPool.getResource();  
  144.             jedis.hmset(key, map);  
  145.             jedisPool.returnResource(jedis);  
  146.         } catch (Exception e) {  
  147.             log.error(e);  
  148.             if (jedis != null) {  
  149.                 jedisPool.returnBrokenResource(jedis);  
  150.             }  
  151.             throw new JedisException(e);  
  152.         }  
  153.     }  
  154.     /** 
  155.       * 给key赋值,并生命周期设置为seconds 
  156.      */  
  157.     public void setex(String key, int seconds, String value) {  
  158.         Jedis jedis = null;  
  159.         try {  
  160.              jedis = jedisPool.getResource();  
  161.             jedis.setex(key, seconds, value);  
  162.             jedisPool.returnResource(jedis);  
  163.          } catch (Exception e) {  
  164.             log.error(e);  
  165.             if (jedis != null) {  
  166.                 jedisPool.returnBrokenResource(jedis);  
  167.             }  
  168.             throw new JedisException(e);  
  169.         }  
  170.     }  
  171.     /** 
  172.      * 给key赋值,并生命周期设置为seconds 
  173.      */  
  174.     public byte[] setex(byte[] key, byte[] value, int seconds) {  
  175.         Jedis jedis = null;  
  176.         try {  
  177.              jedis = jedisPool.getResource();  
  178.             jedis.setex(key, seconds, value);  
  179.             jedisPool.returnResource(jedis);  
  180.             return value;  
  181.         } catch (Exception e) {  
  182.             log.error(e);  
  183.             if (jedis != null) {  
  184.                 jedisPool.returnBrokenResource(jedis);  
  185.             }  
  186.             throw new JedisException(e);  
  187.         }  
  188.           
  189.   
  190.     }  
  191.     /** 
  192.      * 为给定key设置生命周期 
  193.      */  
  194.     public void expire(String key, int seconds) {  
  195.         Jedis jedis = null;  
  196.         try {  
  197.              jedis = jedisPool.getResource();  
  198.             jedis.expire(key, seconds);  
  199.             jedisPool.returnResource(jedis);  
  200.         } catch (Exception e) {  
  201.             log.error(e);  
  202.             if (jedis != null) {  
  203.                 jedisPool.returnBrokenResource(jedis);  
  204.             }  
  205.              throw new JedisException(e);  
  206.         }  
  207.     }  
  208.     /** 
  209.      * 检查key是否存在 
  210.      */  
  211.     public boolean exists(String key) {  
  212.         Jedis jedis = null;  
  213.         try {  
  214.             jedis = jedisPool.getResource();  
  215.             boolean bool = jedis.exists(key);  
  216.             jedisPool.returnResource(jedis);  
  217.             return bool;  
  218.         } catch (Exception e) {  
  219.             log.error(e);  
  220.             if (jedis != null) {  
  221.                 jedisPool.returnBrokenResource(jedis);  
  222.             }  
  223.             throw new JedisException(e);  
  224.         }  
  225.     }  
  226.         /** 
  227.      * 检查key是否存在 
  228.      */  
  229.     public boolean exists(byte[] key) {  
  230.         Jedis jedis = null;  
  231.         try {  
  232.             jedis = jedisPool.getResource();  
  233.             Set<byte[]> hashSet = jedis.keys(key);  
  234.             jedisPool.returnResource(jedis);  
  235.             if (null != hashSet && hashSet.size() >0 ){  
  236.                 return true;  
  237.             }else{  
  238.                 return false;  
  239.             }  
  240.   
  241.         } catch (Exception e) {  
  242.              log.error(e);  
  243.             if (jedis != null) {  
  244.                 jedisPool.returnBrokenResource(jedis);  
  245.             }  
  246.             throw new JedisException(e);  
  247.         }  
  248.     }  
  249.     /** 
  250.      * 返回key值的类型 none(key不存在),string(字符串),list(列表),set(集合),zset(有序集),hash(哈希表) 
  251.      */  
  252.     public String type(String key) {  
  253.         Jedis jedis = null;  
  254.         try {  
  255.             jedis = jedisPool.getResource();  
  256.             String type = jedis.type(key);  
  257.             jedisPool.returnResource(jedis);  
  258.             return type;  
  259.         } catch (Exception e) {  
  260.             log.error(e);  
  261.             if (jedis != null) {  
  262.                 jedisPool.returnBrokenResource(jedis);  
  263.             }  
  264.             throw new JedisException(e);  
  265.         }  
  266.     }  
  267.     /** 
  268.      * 从哈希表key中获取field的value 
  269.      */  
  270.     public String hget(String key, String field) {  
  271.         Jedis jedis = null;  
  272.         try {  
  273.              jedis = jedisPool.getResource();  
  274.             String value = jedis.hget(key, field);  
  275.             jedisPool.returnResource(jedis);  
  276.             return value;  
  277.         } catch (Exception e) {  
  278.             log.error(e);  
  279.             if (jedis != null) {  
  280.                 jedisPool.returnBrokenResource(jedis);  
  281.             }  
  282.             throw new JedisException(e);  
  283.         }  
  284.     }  
  285.     /** 
  286.      * 返回哈希表key中,所有的域和值 
  287.      */  
  288.     public Map<String, String> hgetAll(String key) {  
  289.         Jedis jedis = null;  
  290.         try {  
  291.              jedis = jedisPool.getResource();  
  292.             Map<String, String> map = jedis.hgetAll(key);  
  293.             jedisPool.returnResource(jedis);  
  294.             return map;  
  295.         } catch (Exception e) {  
  296.              log.error(e);  
  297.             if (jedis != null) {  
  298.                 jedisPool.returnBrokenResource(jedis);  
  299.             }  
  300.             throw new JedisException(e);  
  301.         }  
  302.   
  303.     }  
  304.     /** 
  305.      * 返回哈希表key中,所有的域和值 
  306.      */  
  307.     public Set<?> smembers(String key) {  
  308.         Jedis jedis = null;  
  309.         try {  
  310.             jedis = jedisPool.getResource();  
  311.              Set<?> set = jedis.smembers(key);  
  312.             jedisPool.returnResource(jedis);  
  313.             return set;  
  314.         } catch (Exception e) {  
  315.             log.error(e);  
  316.             if (jedis != null) {  
  317.                 jedisPool.returnBrokenResource(jedis);  
  318.             }  
  319.              throw new JedisException(e);  
  320.         }  
  321.     }     
  322.     /** 
  323.      * 返回匹配的 keys 列表 
  324.      */  
  325.      public Set<byte[]> keys(String pattern) {  
  326.         Jedis jedis = null;  
  327.         try {  
  328.             jedis = jedisPool.getResource();  
  329.             Set<byte[]> keys = jedis.keys(pattern.getBytes());  
  330.             jedisPool.returnResource(jedis);  
  331.             return keys;  
  332.         } catch (Exception e) {  
  333.             log.error(e);  
  334.             if (jedis != null) {  
  335.                 jedisPool.returnBrokenResource(jedis);  
  336.             }  
  337.             throw new JedisException(e);  
  338.         }  
  339.   
  340.     }  
  341.     /** 
  342.      * 移除set集合中的member元素 
  343.      */  
  344.     public void delSetObj(String key, String field) {  
  345.         Jedis jedis = null;  
  346.         try {  
  347.             jedis = jedisPool.getResource();  
  348.             jedis.srem(key, field);  
  349.             jedisPool.returnResource(jedis);  
  350.         } catch (Exception e) {  
  351.             log.error(e);  
  352.             if (jedis != null) {  
  353.                 jedisPool.returnBrokenResource(jedis);  
  354.             }  
  355.             throw new JedisException(e);  
  356.         }  
  357.     }  
  358.     /** 
  359.      * 删除元素 
  360.      */  
  361.     public void del(byte[] key) {  
  362.          Jedis jedis = null;  
  363.         try {  
  364.             jedis = jedisPool.getResource();  
  365.             jedis.del(key);  
  366.             jedisPool.returnResource(jedis);  
  367.         } catch (Exception e) {  
  368.             log.error(e);  
  369.             if (jedis != null) {  
  370.                 jedisPool.returnBrokenResource(jedis);  
  371.             }  
  372.             throw new JedisException(e);  
  373.         }  
  374.     }  
  375.     /** 
  376.      * 判断member元素是否是集合key的成员。是(true),否则(false) 
  377.      */  
  378.     public boolean isNotField(String key, String field) {  
  379.         Jedis jedis = null;  
  380.         try {  
  381.             jedis = jedisPool.getResource();  
  382.              boolean bool = jedis.sismember(key, field);  
  383.             jedisPool.returnResource(jedis);  
  384.              return bool;  
  385.         } catch (Exception e) {  
  386.              log.error(e);  
  387.             if (jedis != null) {  
  388.                 jedisPool.returnBrokenResource(jedis);  
  389.             }  
  390.             throw new JedisException(e);  
  391.         }  
  392.     }  
  393.     /** 
  394.      * 如果key已经存在并且是一个字符串,将value追加到key原来的值之后 
  395.      */  
  396.     public void append(String key, String value) {  
  397.         Jedis jedis = null;  
  398.         try {  
  399.             jedis = jedisPool.getResource();  
  400.             jedis.append(key, value);  
  401.             jedisPool.returnResource(jedis);  
  402.         } catch (Exception e) {  
  403.             log.error(e);  
  404.             if (jedis != null) {  
  405.                 jedisPool.returnBrokenResource(jedis);  
  406.             }  
  407.             throw new JedisException(e);  
  408.         }  
  409.     }  
  410.     /** 
  411.      * 清空当前的redis 库 
  412.      */  
  413.     public void flushDB() {  
  414.         Jedis jedis = null;  
  415.         try {  
  416.             jedis = jedisPool.getResource();  
  417.             jedis.flushDB();  
  418.             jedisPool.returnResource(jedis);  
  419.         } catch (Exception e) {  
  420.             log.error(e);  
  421.             if (jedis != null) {  
  422.                 jedisPool.returnBrokenResource(jedis);  
  423.             }  
  424.             throw new JedisException(e);  
  425.         }  
  426.   
  427.      }  
  428.     /** 
  429.      * 返回当前redis库所存储数据的大小 
  430.      */  
  431.     public Long dbSize() {  
  432.           
  433.         Long dbSize = 0L;  
  434.           
  435.         Jedis jedis = null;  
  436.         try {  
  437.             jedis = jedisPool.getResource();  
  438.              jedis.dbSize();  
  439.             jedisPool.returnResource(jedis);  
  440.             return dbSize;  
  441.         } catch (Exception e) {  
  442.             log.error(e);  
  443.             if (jedis != null) {  
  444.                 jedisPool.returnBrokenResource(jedis);  
  445.             }  
  446.             throw new JedisException(e);  
  447.         }  
  448.   
  449.     }  
  450.     /** 
  451.      * 关闭 Redis 
  452.      */  
  453.     public void destory() {  
  454.         jedisPool.destroy();  
  455.     }  
  456.   
  457.        public JedisPool getJedisPool() {  
  458.         return jedisPool;  
  459.     }  
  460.     public void setJedisPool(JedisPool jedisPool) {  
  461.         this.jedisPool = jedisPool;  
  462.     }  
  463. }  
JedisPool 管理类 ,对redis的java客户端jedis的封装

     (7)com.securityframework.support.redis.RedisCacheManager

  1. public class RedisCacheManager implements CacheManager {  
  2.   
  3.     private static final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);  
  4.   
  5.     // fast lookup by name map  
  6.     private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();  
  7.   
  8.     private JedisPoolManager redisManager;  
  9.   
  10.     public <K, V> Cache<K, V> getCache(String name) throws CacheException {  
  11.         logger.debug("获取名称为: " + name + " 的RedisCache实例");  
  12.         Cache c = caches.get(name);  
  13.         if (c == null) {  
  14.             c = new RedisCache<K, V>(redisManager);  
  15.             caches.put(name, c);  
  16.         }  
  17.         return c;  
  18.     }  
  19.         //setter和getter方法省略  
  20. }  
     RedisCacheManager实现org.apache.shiro.cache.CacheManager接口,是shiro使用redis的缓存

     (8)com.securityframework.support.redis.RedisSessionDAO

  1. public class RedisSessionDAO extends AbstractSessionDAO {  
  2.   
  3.     private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);  
  4.     /** 
  5.      * shiro-redis的session对象前缀 
  6.      */  
  7.     private final String SHIRO_REDIS_SESSION_PRE = "shiro_redis_session:";  
  8.       
  9.     /** 
  10.      * 存放uid的对象前缀 
  11.      */  
  12.     private final String SHIRO_SHESSIONID_PRE = "shiro_sessionid:";  
  13.       
  14.     /** 
  15.      * 存放uid 当前状态的前缀 
  16.      */  
  17.     private final String UID_PRE = "uid:";  
  18.       
  19.     /** 
  20.      * 存放用户权限的前缀 
  21.      */  
  22.     private final String PERMISSION_PRE ="permission:";  
  23.   
  24.        private JedisPoolManager redisManager;  
  25.   
  26.     private long expire=180000;  
  27.       
  28.     @Override  
  29.     public void update(Session session) throws UnknownSessionException {  
  30.         this.saveSession(session);  
  31.     }  
  32.   
  33.     /** 
  34.      * save session 
  35.      *  
  36.      * @param session 
  37.      * @throws UnknownSessionException 
  38.      */  
  39.     private void saveSession(Session session) throws UnknownSessionException {  
  40.         if (session == null || session.getId() == null) {  
  41.             logger.error("session or session id is null");  
  42.             return;  
  43.         }  
  44.         session.setTimeout(expire);  
  45.         Long redisExpire = expire/1000;  
  46.         int timeout = redisExpire.intValue();  
  47.             JedisPool jedisPool = this.redisManager.getJedisPool();  
  48.         Jedis jedis = null;  
  49.         try {  
  50.             jedis =  jedisPool.getResource();             
  51.             //保存用户会话  
  52.             jedis.setex(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()), timeout, SerializeUtils.serialize(session));  
  53.             String uid = this.getUserId(session);  
  54.             if (null != uid && !"".equals(uid)){  
  55.                 //保存用户会话对应的UID  
  56.                 jedis.setex(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()),timeout, uid.getBytes());  
  57.                 //保存在线UID  
  58.                 jedis.setex(this.getByteKey(this.UID_PRE,uid), timeout,"online".getBytes());  
  59.             }  
  60.             jedisPool.returnResource(jedis);  
  61.         }catch(Exception ex){  
  62.             if (jedis != null) {  
  63.                 jedisPool.returnBrokenResource(jedis);  
  64.             }  
  65.             throw new JedisException(ex);  
  66.         }  
  67.           
  68.           
  69.     }  
  70.       
  71.     @Override  
  72.     public void delete(Session session) {  
  73.         if (session == null || session.getId() == null) {  
  74.             logger.error("session or session id is null");  
  75.             return;  
  76.         }  
  77.           
  78.         JedisPool jedisPool = this.redisManager.getJedisPool();  
  79.         Jedis jedis = null;  
  80.         try {  
  81.             jedis =  jedisPool.getResource();  
  82.               
  83.             //删除用户会话  
  84.             jedis.del(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()));  
  85.             //获取缓存的用户会话对应的UID  
  86.             byte[] uid = jedis.get(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));  
  87.               
  88.             //删除用户会话对应的UID  
  89.             jedis.del(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));  
  90.               
  91.             //删除在线UID  
  92.             jedis.del(this.getByteKey(this.UID_PRE,new String(uid)));  
  93.               
  94.             //删除用户缓存的权限  
  95.             jedis.del(this.getByteKey(this.PERMISSION_PRE, new String(uid)));  
  96.               
  97.             jedisPool.returnResource(jedis);  
  98.         }catch(Exception ex){  
  99.             if (jedis != null) {  
  100.                 jedisPool.returnBrokenResource(jedis);  
  101.             }  
  102.             throw new JedisException(ex);  
  103.         }  
  104.       
  105.     }  
  106.   
  107.         @Override  
  108.     public Collection<Session> getActiveSessions() {  
  109.         Set<Session> sessions = new HashSet<Session>();  
  110.   
  111.         Set<byte[]> keys = redisManager  
  112.                 .keys(this.SHIRO_REDIS_SESSION_PRE + "*");  
  113.         if (keys != null && keys.size() > 0) {  
  114.             for (byte[] key : keys) {  
  115.                 Session s = (Session) SerializeUtils.deserialize(redisManager  
  116.                         .get(key));  
  117.                 sessions.add(s);  
  118.             }  
  119.         }  
  120.   
  121.         return sessions;  
  122.     }  
  123.       
  124.     public boolean isOnLine(String uid){  
  125.           
  126.         Set<byte[]>keys = redisManager.keys(this.UID_PRE + uid);  
  127.         if (keys != null && keys.size() > 0){  
  128.           return true;  
  129.         }  
  130.         return false;  
  131.     }  
  132.   
  133.     @Override  
  134.     protected Serializable doCreate(Session session) {  
  135.         Serializable sessionId = this.generateSessionId(session);  
  136.         this.assignSessionId(session, sessionId);  
  137.         this.saveSession(session);  
  138.         return sessionId;  
  139.     }  
  140.   
  141.     @Override  
  142.     protected Session doReadSession(Serializable sessionId) {  
  143.         if (sessionId == null) {  
  144.             logger.error("session id is null");  
  145.             return null;  
  146.         }  
  147.           
  148.         logger.debug("#####Redis.SessionId=" + new String(getByteKey(this.SHIRO_REDIS_SESSION_PRE,sessionId)));  
  149.           
  150.         Session s = (Session) SerializeUtils.deserialize(redisManager.get(this  
  151.                 .getByteKey(this.SHIRO_REDIS_SESSION_PRE,sessionId)));  
  152.         return s;  
  153.     }  
  154.       
  155.     /** 
  156.      * 获得byte[]型的key 
  157.      *  
  158.      * @param key 
  159.      * @return 
  160.      */  
  161.     private byte[] getByteKey(String preKey,Serializable sessionId) {  
  162.         String key = preKey + sessionId;  
  163.         return key.getBytes();  
  164.       
  165.     }  
  166.       
  167.     /** 
  168.      * 获取用户唯一标识 
  169.      * @param session 
  170.      * @return 
  171.      */  
  172.     private String getUserId(Session session){  
  173.         SimplePrincipalCollection pricipal = (SimplePrincipalCollection)session.getAttribute("org.apache.shiro.subject.support.DefaultSubjectContext_PRINCIPALS_SESSION_KEY");  
  174.         if (null != pricipal){  
  175.             Account account = ((Account) pricipal.getPrimaryPrincipal());  
  176.             return account.getAccountId();  
  177.         }  
  178.         return  "";  
  179.     }  
  180.     //setter和getter省略  
  181.   
  182. }  
    RedisSessionDAO继承org.apache.shiro.session.mgt.eis.AbstractSessionDAO,而AbstractSessionDAO是实现了org.apache.shiro.session.mgt.eis.SessionDAO接口的。    通过redis实现shiro的CacheManager接口,继承AbstractSessionDAO,实现shiro和redis的整合。
本项目详细介绍请看:http://www.sojson.com/shiro (强烈推荐) Demo已经部署到线上,地址是http://shiro.itboy.net, 管理员帐号:admin,密码:sojson.com 如果密码错误,请用sojson。 PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快,有问题加群解决。 声明: 本人提供这个Shiro + SpringMvc + Mybatis + Redis 的Demo 本着学习的态度,如果有欠缺和不足的地方,给予指正,并且多多包涵。 “去其糟粕取其精华”。如果觉得写的好的地方就给个赞,写的不好的地方,也请多多包涵。 使用过程: 1.创建数据库。 创建语句 :tables.sql 2.插入初始化数据 插入初始化数据:init.data.sql 3.运行。 管理员帐号:admin 密码:sojson ps:定时任务的sql会把密码改变为sojson.com 新版本说明:http://www.sojson.com/blog/164.html 和 http://www.sojson.com/blog/165.html 主要解决是之前说的问题:Shiro 教程,关于最近反应的相关异常问题,解决方法合集。 项目在本页面的附件中提取。 一、Cache配置修改。 配置文件(spring-cache.xml )中已经修改为如下配置: <!-- redis 配置,也可以把配置挪到properties配置文件中,再读取 --> <!-- 这种 arguments 构造的方式,之前配置有缺点。 这里之前的配置有问题,因为参数类型不一致,有时候jar和环境的问题,导致参数根据index对应,会处理问题, 理论上加另一个 name,就可以解决,现在把name 和type都加上,更保险。 --> 二、登录获取上一个URL地址报错。 当没有获取到退出前的request ,为null 的时候会报错。在(UserLoginController.java )135行处有所修改。 /** * shiro 获取登录之前的地址 * 之前0.1版本这个没判断空。 */ SavedRequest savedRequest = WebUtils.getSavedRequest(request); String url = null ; if(null != savedRequest){ url = savedRequest.getRequestUrl(); } /** * 我们平常用的获取上一个请求的方式,在Session不一致的情况下是获取不到的 * String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE); */ 三、删除了配置文件中的cookie写入域的问题。 在配置文件里(spring-shiro.xml )中的配置有所修改。 <!-- 会话Cookie模板 --> <!--cookie的name,我故意取名叫xxxxbaidu --> <!--cookie的有效时间 --> <!-- 配置存储Session Cookie的domain为 一级域名 --> 上面配置是去掉了 Session 的存储Key 的作用域,之前设置的.itboy.net ,是写到当前域名的 一级域名 下,这样就可以做到N 个 二级域名 下,三级、四级....下 Session 都是共享的。 <!-- 用户信息记住我功能的相关配置 --> <!-- 配置存储rememberMe Cookie的domain为 一级域名 --> <!-- 30天时间,记住我30天 --> 记住我登录的信息配置。和上面配置是一样的道理,可以在相同 一级域名 下的所有域名都可以获取到登录的信息。 四、简单实现了单个帐号只能在一处登录。 我们在其他的系统中可以看到,单个帐号只允许一人使用,在A处登录了,B处再登录,那A处就被踢出了。如下图所示。 但是此功能不是很完美,当A处被踢出后,再重新登录,这时候B处反应有点慢,具体我还没看,因为是之前加的功能,现在凌晨了,下次我有空再瞧瞧,同学你也可以看看,解决了和我说一声,我把功能修复。 五、修复功能(BUG) 1.修复权限添加功能BUG。 之前功能有问题,每当添加一个权限的时候,默认都给角色为“管理员”的角色默认添加当前新添加的权限。这样达到管理员的权限永远是最大的。由于代码有BUG ,导致所有权限删除了。现已修复。 2.修复项目只能部署到Root目录下的问题。 问题描述:之前项目只能部署到Root 下才能正常运行,目前已经修复,可以带项目路径进行访问了,之前只能这样访问,http://localhost:8080 而不能http://localhost:8080/shiro.demo/ 访问,目前是可以了。 解决方案:在 FreeMarkerViewExtend.java 33行处 增加了BasePath ,通过BasePath 来控制请求目录,在 Freemarker 中可以自由使用,而 JSP 中是直接在 JSP 中获取BasePath 使用。 解决后遗症:因为我们的权限是通过URL 来控制的,那么增加了项目的目录,导致权限不能正确的判断,再加上我们的项目名称(目录)可以自定义,导致更不好判断。 后遗症解决方案:PermissionFilter.java 50行处 解决了这个问题,详情请看代码和注释,其实就是replace 了一下。 HttpServletRequest httpRequest = ((HttpServletRequest)request); /** * 此处是改版后,为了兼容项目不需要部署到root下,也可以正常运行,但是权限没设置目前必须到root 的URI, * 原因:如果你把这个项目叫 ShiroDemo,那么路径就是 /ShiroDemo/xxxx.shtml ,那另外一个人使用,又叫Shiro_Demo,那么就要这么控制/Shiro_Demo/xxxx.shtml * 理解了吗? * 所以这里替换了一下,使用根目录开始的URI */ String uri = httpRequest.getRequestURI();//获取URI String basePath = httpRequest.getContextPath();//获取basePath if(null != uri && uri.startsWith(basePath)){ uri = uri.replace(basePath, ""); } 3.项目启动的时候报错,关于JNDI的错误提示。 其实也不是错,但是看着不舒服,所以还得解决这个问题。解决这个问题需要在web.xml 中的开始部位加入以下代码。 spring.profiles.active dev spring.profiles.default dev spring.liveBeansView.mbeanDomain dev 4.项目Maven打包问题。 打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码(群里同学提供的)。 src/main/java **/*.properties **/*.xml false 在 标签内加入即可,如果还是不能解决,那么请你加群(改名后)说明你的问题,有人会回答你。 5.Tomcat7以上在访问JSP页面的时候,提示JSTL错误。 这个错误是因为Tomcat7 中没有 JSTL 的jar包,现在已经在项目pom.xml 中增加了如下 jar 的引入管理。 javax.servlet jstl 1.2 javax.servlet jsp-api 2.0 provided 如果还是不能解决问题,请在官方群(群号:259217951)内搜索“jstl” 如图下载依赖包。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值