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

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

1、配置web.xml

    <filter>
        <filter-name>ShiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>ShiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
2、配置spring-shiro.xml的配置文件

    <!--shiro配置--> 
    <!--securityManager是shiro核心部分-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
         <property name="sessionManager" ref="webSessionManager" />
         <property name="realm" ref="restfulAuthRealm"/>
         <property name="rememberMeManager.cookie.name" value="rememberMe"/>
    	 <property name="rememberMeManager.cookie.maxAge" value="${rememberMeManager.cookie.maxAge}"/>
    </bean>
    <!--配置shiro的sessionManager-->
    <bean id="webSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    	 <property name="sessionDAO" ref="redisSessionDAO"></property>
    </bean>
    <!--权限操作bean-->
    <bean id="permissionManager" class="com.securityframework.local.PermissionManagerLocalImpl" />
    <!--账号操作bean-->
    <bean id="accountManagerImpl" class="com.securityframework.local.AccountManagerLocalImpl"/>
    <!--自定义realm-->
    <bean id ="restfulAuthRealm" class="com.isoftstone.securityframework.restful.client.web.shiro.realm.RestAuthRealm">
	    <property name="accountManagerImpl" ref="accountManagerImpl"></property>
	    <property name="permissionManagerImpl" ref="permissionManager"></property>
	    <property name="cacheManager" ref="redisCacheManager"></property>
            <property name="platformLabel">
		 <value>${platformLabel}</value>
	    </property>
     </bean>     
     <!--动态获取filterchaindefinitions,此处与下面ShiroFilter bean所引用的类对应-->
     <bean id="systemUrlChainManager" class="com.securityframework.restful.client.web.shiro.mgt.RestUrlChainManager">
	      <property name="permissionManager" ref="permissionManager"></property>
		 <property name="platformLabel">
			 <value>${platformLabel}</value>
		 </property>
		<property name="systemLabel">
 			<value>${systemLabel}</value>
		</property>
      </bean>
      <!--与web.xml中配置的filter同名,它对应的类原本是<code class="xml string">org.apache.shiro.spring.web.ShiroFilterFactoryBean,</code>-->
      <!--这里为了动态获取filterchaindefinitions改写了<code class="xml string">ShiroFilterFactoryBean类,它们的作用是一样的</code>--> 
      <bean id="ShiroFilter" class="com.securityframework.restful.client.web.shiro.filter.RestAuthShiroFilter">
        <property name="urlChainManager" ref="systemUrlChainManager" />
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="../../res/user/login.html"/>
        <property name="unauthorizedUrl" value="/html/413.html"/>
        <property name="filters">
            <util:map>
                <entry key="authc">
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>
                </entry>
            </util:map>
        </property>                      
        <property name="filterChainDefinitions">
            <value>
            	/images/** =anon
            	/help/** =anon
            	/css/** = anon
            	/easyui/** =anon
            	/javascript/** =anon
            	/commons/** =anon
            	/jsplugin/** =anon
            	/ueditor/** =anon
            	/html/** =anon          	
            	/index.html = anon
            	/ = anon
             	/** = user
            </value>
         </property>
    </bean>
<span><span class="comments">    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --></span><span></span></span>
<pre name="code" class="java">    <bean id="lifecycleBeanPostProcessor"   class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 
     
     <!--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        

public class RestUrlChainManager {
	PermissionManager permissionManager; 
	
	private String platformLabel ;
	
	private String systemLabel;
	
	public Map<String,String> buildChainMap(){
		
		Map<String,String> p = new HashMap<String,String>();
		//获取权限信息,以便获得每个权限下面的资源
		List<com.isoftstone.securityframework.api.Permission> perms = permissionManager.findSubsystemPermission(platformLabel, systemLabel);
		
		if(null != perms && perms.size() > 0){
			System.out.println(" SystemUrlChainManager.buildChainMap----- STATUS_OK -----");
		}
		if (null != perms){
			String value ;
			for (int i = 0; i < perms.size(); i++) {
				value = "";
				com.isoftstone.securityframework.api.Permission perm = perms.get(i);
				if(i == 0){
					value = "authc," + perm.getPermissionName();
				}else{
					value = perm.getPermissionName();
				}
				List<com.isoftstone.securityframework.api.Resource> resources = perm.getResources();
				
				if(null != resources){
					for (int j = 0; j < resources.size(); j++) {
						com.isoftstone.securityframework.api.Resource resource = resources.get(j);
                                                //格式{'mvc/web/usermgt/add.json','perms[com.securitycenter.user:ADD]'},它
                                                //对应spring-shiro.xml配置文件中ShiroFilter bean下的filterChainDefinitions
                                                p.put(resource.getRes(), String.format("perms[%s]", value));
					}
				}
			}
		}
		return p;
	}

        /**
         *  setter和getter方法省略
         **/
 }
      RestUrlChainManager类中的buildChainMap方法是从数据库获取资源,组成动态的filterChainDefinitions,以便系统对所有的资源请求的拦截都可以动态可配置

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

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

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

/**
 * JedisPool 管理类 
 * 用于单个redis 集群, 每个redis集群由master-salve组成
 */
public class JedisPoolManager {

	private static Log log = LogFactory.getLog(JedisPoolManager.class);

	private JedisPool jedisPool;
	/**
	 * redis的List集合 ,向key这个list添加元素
	 */
	public long rpush(String key, String string) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			long ret = jedis.rpush(key, string);
			jedisPool.returnResource(jedis);
			return ret;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 获取key这个List,从第几个元素到第几个元素 LRANGE key start
	 * stop返回列表key中指定区间内的元素,区间以偏移量start和stop指定。
	 * 下标(index)参数start和stop都以0为底,也就是说,以0表示列表的第一个元素,以1表示列表的第二个元素,以此类推。
	 * 也可以使用负数下标,以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。
	 */
	public List<String> lrange(String key, long start, long end) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			List<String> ret = jedis.lrange(key, start, end);
			jedisPool.returnResource(jedis);
			return ret;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 将哈希表key中的域field的值设为value。
	 */
	public void hset(String key, String field, String value) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			jedis.hset(key, field, value);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 向key赋值
	 */
	public void set(String key, String value) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			jedis.set(key, value);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 向key赋值
	 */
	public void set(byte[] key, byte[] value) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			jedis.set(key, value);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 获取key的值
	 */
	public String get(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			String value = jedis.get(key);
			jedisPool.returnResource(jedis);
			return value;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 获取key的值
	 */
	public byte[] get(byte[] key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			byte[] value = jedis.get(key);
			jedisPool.returnResource(jedis);
			return value;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}

	}
	/**
	 * 将多个field - value(域-值)对设置到哈希表key中。
	 */
	public void hmset(String key, Map<String, String> map) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			jedis.hmset(key, map);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	  * 给key赋值,并生命周期设置为seconds
	 */
	public void setex(String key, int seconds, String value) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			jedis.setex(key, seconds, value);
			jedisPool.returnResource(jedis);
		 } catch (Exception e) {
			log.error(e);
			if (jedis != null) {
 				jedisPool.returnBrokenResource(jedis);
 			}
			throw new JedisException(e);
		}
	}
	/**
	 * 给key赋值,并生命周期设置为seconds
	 */
	public byte[] setex(byte[] key, byte[] value, int seconds) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			jedis.setex(key, seconds, value);
			jedisPool.returnResource(jedis);
			return value;
		} catch (Exception e) {
			log.error(e);
 			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
		

	}
	/**
	 * 为给定key设置生命周期
	 */
	public void expire(String key, int seconds) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			jedis.expire(key, seconds);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			 throw new JedisException(e);
		}
	}
	/**
	 * 检查key是否存在
	 */
	public boolean exists(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			boolean bool = jedis.exists(key);
			jedisPool.returnResource(jedis);
			return bool;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
        /**
	 * 检查key是否存在
	 */
	public boolean exists(byte[] key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
		    Set<byte[]> hashSet = jedis.keys(key);
		    jedisPool.returnResource(jedis);
		    if (null != hashSet && hashSet.size() >0 ){
		    	return true;
		    }else{
		    	return false;
		    }

		} catch (Exception e) {
			 log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 返回key值的类型 none(key不存在),string(字符串),list(列表),set(集合),zset(有序集),hash(哈希表)
	 */
	public String type(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			String type = jedis.type(key);
			jedisPool.returnResource(jedis);
			return type;
 		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 从哈希表key中获取field的value
	 */
	public String hget(String key, String field) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			String value = jedis.hget(key, field);
			jedisPool.returnResource(jedis);
			return value;
 		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 返回哈希表key中,所有的域和值
	 */
	public Map<String, String> hgetAll(String key) {
		Jedis jedis = null;
		try {
			 jedis = jedisPool.getResource();
			Map<String, String> map = jedis.hgetAll(key);
			jedisPool.returnResource(jedis);
			return map;
		} catch (Exception e) {
			 log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}

	}
	/**
	 * 返回哈希表key中,所有的域和值
	 */
	public Set<?> smembers(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			 Set<?> set = jedis.smembers(key);
			jedisPool.returnResource(jedis);
 			return set;
 		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			 throw new JedisException(e);
		}
	}	
	/**
	 * 返回匹配的 keys 列表
	 */
	 public Set<byte[]> keys(String pattern) {
 		Jedis jedis = null;
 		try {
			jedis = jedisPool.getResource();
			Set<byte[]> keys = jedis.keys(pattern.getBytes());
			jedisPool.returnResource(jedis);
			return keys;
 		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}

	}
	/**
	 * 移除set集合中的member元素
	 */
	public void delSetObj(String key, String field) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			jedis.srem(key, field);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
 			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 删除元素
	 */
	public void del(byte[] key) {
		 Jedis jedis = null;
 		try {
			jedis = jedisPool.getResource();
			jedis.del(key);
 			jedisPool.returnResource(jedis);
 		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 判断member元素是否是集合key的成员。是(true),否则(false)
	 */
	public boolean isNotField(String key, String field) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			 boolean bool = jedis.sismember(key, field);
			jedisPool.returnResource(jedis);
			 return bool;
		} catch (Exception e) {
			 log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}
	}
	/**
	 * 如果key已经存在并且是一个字符串,将value追加到key原来的值之后
	 */
	public void append(String key, String value) {
		Jedis jedis = null;
 		try {
 			jedis = jedisPool.getResource();
			jedis.append(key, value);
			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
 			throw new JedisException(e);
		}
	}
	/**
	 * 清空当前的redis 库
	 */
	public void flushDB() {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
 			jedis.flushDB();
 			jedisPool.returnResource(jedis);
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}

	 }
	/**
	 * 返回当前redis库所存储数据的大小
	 */
	public Long dbSize() {
		
		Long dbSize = 0L;
		
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			 jedis.dbSize();
 			jedisPool.returnResource(jedis);
			return dbSize;
		} catch (Exception e) {
			log.error(e);
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(e);
		}

	}
	/**
	 * 关闭 Redis
	 */
	public void destory() {
		jedisPool.destroy();
	}

       public JedisPool getJedisPool() {
		return jedisPool;
	}
  	public void setJedisPool(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}
}
JedisPool 管理类 ,对redis的java客户端jedis的封装

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

public class RedisCacheManager implements CacheManager {

	private static final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);

	// fast lookup by name map
	private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();

	private JedisPoolManager redisManager;

	public <K, V> Cache<K, V> getCache(String name) throws CacheException {
		logger.debug("获取名称为: " + name + " 的RedisCache实例");
		Cache c = caches.get(name);
		if (c == null) {
			c = new RedisCache<K, V>(redisManager);
			caches.put(name, c);
		}
		return c;
	}
        //setter和getter方法省略
}
     RedisCacheManager实现org.apache.shiro.cache.CacheManager接口,是shiro使用redis的缓存

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

public class RedisSessionDAO extends AbstractSessionDAO {

	private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
	/**
	 * shiro-redis的session对象前缀
	 */
	private final String SHIRO_REDIS_SESSION_PRE = "shiro_redis_session:";
	
	/**
	 * 存放uid的对象前缀
	 */
	private final String SHIRO_SHESSIONID_PRE = "shiro_sessionid:";
	
	/**
	 * 存放uid 当前状态的前缀
	 */
	private final String UID_PRE = "uid:";
	
	/**
	 * 存放用户权限的前缀
	 */
	private final String PERMISSION_PRE ="permission:";

       private JedisPoolManager redisManager;

	private long expire=180000;
	
	@Override
	public void update(Session session) throws UnknownSessionException {
		this.saveSession(session);
	}

	/**
	 * save session
	 * 
	 * @param session
	 * @throws UnknownSessionException
	 */
	private void saveSession(Session session) throws UnknownSessionException {
		if (session == null || session.getId() == null) {
			logger.error("session or session id is null");
			return;
		}
	    session.setTimeout(expire);
	    Long redisExpire = expire/1000;
	    int timeout = redisExpire.intValue();
	    	JedisPool jedisPool = this.redisManager.getJedisPool();
		Jedis jedis = null;
		try {
			jedis =  jedisPool.getResource();			
			//保存用户会话
			jedis.setex(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()), timeout, SerializeUtils.serialize(session));
			String uid = this.getUserId(session);
			if (null != uid && !"".equals(uid)){
				//保存用户会话对应的UID
				jedis.setex(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()),timeout, uid.getBytes());
				//保存在线UID
				jedis.setex(this.getByteKey(this.UID_PRE,uid), timeout,"online".getBytes());
			}
            jedisPool.returnResource(jedis);
		}catch(Exception ex){
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(ex);
		}
		
		
	}
	
	@Override
	public void delete(Session session) {
		if (session == null || session.getId() == null) {
			logger.error("session or session id is null");
			return;
		}
		
		JedisPool jedisPool = this.redisManager.getJedisPool();
		Jedis jedis = null;
		try {
			jedis =  jedisPool.getResource();
			
			//删除用户会话
			jedis.del(this.getByteKey(this.SHIRO_REDIS_SESSION_PRE,session.getId()));
			//获取缓存的用户会话对应的UID
			byte[] uid = jedis.get(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));
			
			//删除用户会话对应的UID
			jedis.del(this.getByteKey(this.SHIRO_SHESSIONID_PRE,session.getId()));
			
			//删除在线UID
			jedis.del(this.getByteKey(this.UID_PRE,new String(uid)));
			
			//删除用户缓存的权限
			jedis.del(this.getByteKey(this.PERMISSION_PRE, new String(uid)));
			
            jedisPool.returnResource(jedis);
		}catch(Exception ex){
			if (jedis != null) {
				jedisPool.returnBrokenResource(jedis);
			}
			throw new JedisException(ex);
		}
	
 	}

        @Override
	public Collection<Session> getActiveSessions() {
		Set<Session> sessions = new HashSet<Session>();

		Set<byte[]> keys = redisManager
				.keys(this.SHIRO_REDIS_SESSION_PRE + "*");
		if (keys != null && keys.size() > 0) {
			for (byte[] key : keys) {
				Session s = (Session) SerializeUtils.deserialize(redisManager
						.get(key));
				sessions.add(s);
			}
		}

		return sessions;
	}
	
	public boolean isOnLine(String uid){
		
		Set<byte[]>keys = redisManager.keys(this.UID_PRE + uid);
		if (keys != null && keys.size() > 0){
		  return true;
		}
		return false;
	}

	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = this.generateSessionId(session);
		this.assignSessionId(session, sessionId);
		this.saveSession(session);
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		if (sessionId == null) {
			logger.error("session id is null");
			return null;
		}
		
		logger.debug("#####Redis.SessionId=" + new String(getByteKey(this.SHIRO_REDIS_SESSION_PRE,sessionId)));
		
		Session s = (Session) SerializeUtils.deserialize(redisManager.get(this
				.getByteKey(this.SHIRO_REDIS_SESSION_PRE,sessionId)));
		return s;
	}
	
	/**
	 * 获得byte[]型的key
	 * 
	 * @param key
	 * @return
	 */
	private byte[] getByteKey(String preKey,Serializable sessionId) {
		String key = preKey + sessionId;
		return key.getBytes();
	
	}
	
	/**
	 * 获取用户唯一标识
	 * @param session
	 * @return
	 */
	private String getUserId(Session session){
		SimplePrincipalCollection pricipal = (SimplePrincipalCollection)session.getAttribute("org.apache.shiro.subject.support.DefaultSubjectContext_PRINCIPALS_SESSION_KEY");
        if (null != pricipal){
        	Account account = ((Account) pricipal.getPrimaryPrincipal());
        	return account.getAccountId();
        }
        return  "";
	}
	//setter和getter省略

}
    RedisSessionDAO继承org.apache.shiro.session.mgt.eis.AbstractSessionDAO,而AbstractSessionDAO是实现了org.apache.shiro.session.mgt.eis.SessionDAO接口的。

    通过redis实现shiro的CacheManager接口,继承AbstractSessionDAO,实现shiro和redis的整合。


本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

基于方法的JIT编译之挑战 - 2015-05-03 09:05:05

  今天,混合模式的编译系统采用的常用方法是识别频繁执行的或者叫热方法。热方法传递给JIT编译器以便编译成机器代码。然后,当解释器看见应用调用被编译过的方法时,它就会分发机器代码去执行。   这种面向方法的方法已经采用许多年了,但是仍然需要大量的开发方面的前期投资。直到能够编译一门语言中出现的所有功能时,这样的系统才能提高方法的执行效率。对重要的应用来说,这需要JIT编译整个语言,包含那些复杂的已经用高级虚拟指令体实现了的功能,例如那些方法调用,对象创建,异常处理。 1 Compiling Cold Co
本文在前半部分叙述一个听起来十分吸引人且合理的故事,然后紧接着告诉你这个美好的故事事实上几乎不会发生,最后来个总结。在接下来的一篇文章中,我提出一个比较自我的方案。 第一部分:美好的故事 在xtables-addons中,有一个特别有意思的小模块,那就是xt_SYSRQ,它作为一个iptables的target加载进内核,可以在远程为本机发送sysrq命令,这个功能可谓强大。在去年的项目中中,我已经将其部署到了实际的产品中,然而今日再看,发现还是有些美中不足,确实需要改进: 1.原版的xt_SYSRQ没有反

软件体系结构风格 - 2015-05-03 09:05:05

        MarShaw 和 DavidGarlan  中提出的软件体系结构定义为:能够用来具体描述软件系统控制结构和整体组织的一种体系结构,能够表示系统的框架结构,用于从较高的层次上来描述各部分之间的关系和接口。         软件体系结构是对系统的一种高层次的抽象描述。主要是反映拓扑属性,有意忽略细节;         软件体系结构是由构件和构件之间的联系组成,构件又有它自身的体系结构; 构件的描述有 3 个方面:计算功能、结构特性及其他特性。  从软件体系结构的定义可以看出,软件体系结构主要
注:本记录适用于Debian系列Linux操作系统。在Ubuntu 14.10 以及 Linux Mint 17下验证成功。 在综合课程设计的搭建 PPPoE Server 环节中,本人以及组员碰到各种问题。在此总结,以备日后需要。 搭建过程 安装和配置PPPoE程序 PPPoE程序在Debian操作系统中应该是自带的。可以使用 pppoe-server -h 命令查看版本。可以使用 sudo apt-cache search pppoe 查找相关软件。 配置文件存放在 /etc/ppp 文件夹中。先设置
    前些天,在修改密码这问题给困住了,网上肯定有解决办法,也有提高班同学们写的博客,但是记得米老师说过,站在巨人的肩膀上是有前提的,所以还是决定自己解决问题,一定要自己解决。中间因为作品展停了几天,当我再次思考这个问题,调啊调,最终被我解决了,真的是很开心!当时特别兴奋,可能我比别人慢一点,花的时间也多了一点,但没关系,我有收获就行了,再提高的效率,我的进度就能赶上来的。     修改密码的第一步是要核对当前用户,将原密码输入,判断原密码是否正确,而我就卡到了这一块。这个问题,就是保存当前登录用户的用

windows自定义命令的创建 - 2015-05-03 06:05:15

首先在任意位置创建一个文件夹,我使用的目录是 D:\Program Files\Quick Start\command\ ,桌面我的电脑/计算机图标右键属性 高级系统设置 - 高级 - 环境变量 在系统变量中找到 Path ,双击修改,在结尾追加你的目录 D:\Program Files\Quick Start\command\ ,注意和前面的目录用 ; 隔开. 现在回到我们新建的那个目录 复制桌面的QQ快捷方式到这个文件夹,重命名为 qq ,复制迅雷的重命名为 xunlei ,现在 Win + R  

初识Dubbo 系列之7-Dubbo 示例 - 2015-05-03 06:05:12

示例 想完整的运行起来,请参见: 快速启动 ( + ),这里只列出各种场景的配置方式 以下示例全部使用基于Spring的 Xml配置 ( + )作为参考,如果不想使用Spring,而希望通过API的方式进行调用,请参见: API配置 ( + ) 启动时检查 ( + ) ( # ) Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=true。 如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭c

架构师成长历程 - 2015-05-03 06:05:02

 架构师的巅峰似乎很耀眼,但其成长的道路却异常曲折,但是我相信只要能做到脚踏实地、一步一个脚印、慢慢的积累,一切总是会顺理成章!我个人觉得,要成为一名出色的架构师,简言之需要具备以下的必要条件与过程: 1、热情主动的学习      当然不是说我们可以毫无目的的,首先需要知道架构师需要关注的哪些方面,如果你还从Programmer刚起步,不妨在这里多思考和计划一下。最好是能结合自己的项目实际情况,从不同方面进行实践与总结。没有什么可怕的,怕的是我们不去想! 2、善于思考和总结      习惯于将复杂问题简单

设计模式之访问者模式 - 2015-05-02 20:05:57

访问者模式涉及的角色如下: 1  抽象访问者(Visitor)角色:声明了一个或多个方法操作,形成所有具体访问者角色必须实现的接口。 2  具体访问者(ConcreteVisitor)角色:实现抽象访问在所声明的接口,也就是抽象访问者所声明的各个访问操作。 3  抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象所为一个参数 4  具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。 5  结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元
JeeWx(捷微微信管家) 微信API接口 1、jeewx-api为何诞生 现在微信越来越火,基于微信的公众号和服务号越来越丰富,虽然微信帮助文档已经提供了相关的接口,但是接口比较多,通过代码自己调用比较麻烦,所以为减轻开发者独自创造轮子,将微信API进行了统一封装! 2、免责声明 此Api为非官方版,由于官方接口的调整,使用此Api还有可能会出现一些问题 3、快速使用方法: 所有获取微信接口的方法都是静态方法,可以通过传递参数调用,API的包基本与微信开发者文档目录对应,通过英语单据,如参数有疑问,可以