zoukankan      html  css  js  c++  java
  • SpringBoot中用shiro做单点登录

    实际项目中用shiro做权限与登录验证,并做单点登录,单点登录克服有浏览器cookie的sessionID的统一与redis缓存的sessionID统一  也就是所有的sessionID要一致。

    怕忘记并记录下,实际项目redis采用集群。

    一、shiro缓存为redis毋庸置疑

    1、RedisConfig

    package com.sso.common.redis;
    
    import com.sso.common.redis.shiro.FastJsonRedisSerializer;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisClusterConfiguration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.HashSet;
    import java.util.Set;
    
    @Configuration
    @Component
    public class RedisConfig {
    
        @Value("${spring.redis.pool.max-idle}")
        private Integer maxIdle;
    
    //    @Value("${spring.redis.}")
    //    private Integer maxTotal;
    
        @Value("${spring.redis.pool.max-wait}")
        private Integer maxWaitMillis;
    
    //    @Value("${redis.minEvictableIdleTimeMillis}")
    //    private Integer minEvictableIdleTimeMillis;
    
    //    @Value("${redis.numTestsPerEvictionRun}")
    //    private Integer numTestsPerEvictionRun;
    
    //    @Value("${redis.timeBetweenEvictionRunsMillis}")
    //    private long timeBetweenEvictionRunsMillis;
    
    //    @Value("${redis.testOnBorrow}")
    //    private boolean testOnBorrow;
    
    //    @Value("${redis.testWhileIdle}")
    //    private boolean testWhileIdle;
    
    
        @Value("${spring.redis.cluster.nodes}")
        private String clusterNodes;
    
        @Value("${spring.redis.cluster.max-redirects}")
        private Integer mmaxRedirectsac;
        /**
         * JedisPoolConfig 连接池
         *
         * @return
         */
        @Bean
        public JedisPoolConfig jedisPoolConfig() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 最大空闲数
            jedisPoolConfig.setMaxIdle(maxIdle);
            // 连接池的最大数据库连接数
            //jedisPoolConfig.setMaxTotal(maxTotal);
            // 最大建立连接等待时间
            jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
            // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
            //jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
            //jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
            // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
            //jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
            //jedisPoolConfig.setTestOnBorrow(testOnBorrow);
            // 在空闲时检查有效性, 默认false
            //jedisPoolConfig.setTestWhileIdle(testWhileIdle);
            return jedisPoolConfig;
        }
    
        /**
         * Redis集群的配置
         *
         * @return RedisClusterConfiguration
         * @throws
         * @autor lpl
         * @date 2017年12月22日
         */
        @Bean
        public RedisClusterConfiguration redisClusterConfiguration() {
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            //Set<RedisNode> clusterNodes
            String[] serverArray = clusterNodes.split(",");
    
            Set<RedisNode> nodes = new HashSet<RedisNode>();
    
            for (String ipPort : serverArray) {
                String[] ipAndPort = ipPort.split(":");
                nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
            }
    
            redisClusterConfiguration.setClusterNodes(nodes);
            redisClusterConfiguration.setMaxRedirects(mmaxRedirectsac);
            return redisClusterConfiguration;
        }
    
        /**
         * 配置工厂
         *
         * @param @param  jedisPoolConfig
         * @param @return
         * @return JedisConnectionFactory
         * @throws
         * @Title: JedisConnectionFactory
         * @autor lpl
         * @date 2017年12月22日
         */
        @Bean
        public JedisConnectionFactory JedisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
            JedisConnectionFactory JedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
            return JedisConnectionFactory;
        }
    
        @Bean
        public JedisCluster jedisCluster(JedisConnectionFactory JedisConnectionFactory) {
            JedisCluster jedisCluster = (JedisCluster)JedisConnectionFactory.getConnection().getNativeConnection();
            return jedisCluster;
        }
    
    
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            // 使用fastjson序列化
            FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
            // value值的序列化采用fastJsonRedisSerializer
            template.setValueSerializer(fastJsonRedisSerializer);
            template.setHashValueSerializer(fastJsonRedisSerializer);
            // key的序列化采用StringRedisSerializer
            template.setKeySerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
    
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    
    }
    View Code

    2、RedisUtil

    package com.sso.common.redis;
    
    import com.sso.common.redis.shiro.FastJsonRedisSerializer;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisClusterConfiguration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.HashSet;
    import java.util.Set;
    
    @Configuration
    @Component
    public class RedisConfig {
    
        @Value("${spring.redis.pool.max-idle}")
        private Integer maxIdle;
    
    //    @Value("${spring.redis.}")
    //    private Integer maxTotal;
    
        @Value("${spring.redis.pool.max-wait}")
        private Integer maxWaitMillis;
    
    //    @Value("${redis.minEvictableIdleTimeMillis}")
    //    private Integer minEvictableIdleTimeMillis;
    
    //    @Value("${redis.numTestsPerEvictionRun}")
    //    private Integer numTestsPerEvictionRun;
    
    //    @Value("${redis.timeBetweenEvictionRunsMillis}")
    //    private long timeBetweenEvictionRunsMillis;
    
    //    @Value("${redis.testOnBorrow}")
    //    private boolean testOnBorrow;
    
    //    @Value("${redis.testWhileIdle}")
    //    private boolean testWhileIdle;
    
    
        @Value("${spring.redis.cluster.nodes}")
        private String clusterNodes;
    
        @Value("${spring.redis.cluster.max-redirects}")
        private Integer mmaxRedirectsac;
        /**
         * JedisPoolConfig 连接池
         *
         * @return
         */
        @Bean
        public JedisPoolConfig jedisPoolConfig() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 最大空闲数
            jedisPoolConfig.setMaxIdle(maxIdle);
            // 连接池的最大数据库连接数
            //jedisPoolConfig.setMaxTotal(maxTotal);
            // 最大建立连接等待时间
            jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
            // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
            //jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
            //jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
            // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
            //jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
            //jedisPoolConfig.setTestOnBorrow(testOnBorrow);
            // 在空闲时检查有效性, 默认false
            //jedisPoolConfig.setTestWhileIdle(testWhileIdle);
            return jedisPoolConfig;
        }
    
        /**
         * Redis集群的配置
         *
         * @return RedisClusterConfiguration
         * @throws
         * @autor lpl
         * @date 2017年12月22日
         */
        @Bean
        public RedisClusterConfiguration redisClusterConfiguration() {
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            //Set<RedisNode> clusterNodes
            String[] serverArray = clusterNodes.split(",");
    
            Set<RedisNode> nodes = new HashSet<RedisNode>();
    
            for (String ipPort : serverArray) {
                String[] ipAndPort = ipPort.split(":");
                nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
            }
    
            redisClusterConfiguration.setClusterNodes(nodes);
            redisClusterConfiguration.setMaxRedirects(mmaxRedirectsac);
            return redisClusterConfiguration;
        }
    
        /**
         * 配置工厂
         *
         * @param @param  jedisPoolConfig
         * @param @return
         * @return JedisConnectionFactory
         * @throws
         * @Title: JedisConnectionFactory
         * @autor lpl
         * @date 2017年12月22日
         */
        @Bean
        public JedisConnectionFactory JedisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
            JedisConnectionFactory JedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
            return JedisConnectionFactory;
        }
    
        @Bean
        public JedisCluster jedisCluster(JedisConnectionFactory JedisConnectionFactory) {
            JedisCluster jedisCluster = (JedisCluster)JedisConnectionFactory.getConnection().getNativeConnection();
            return jedisCluster;
        }
    
    
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            // 使用fastjson序列化
            FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
            // value值的序列化采用fastJsonRedisSerializer
            template.setValueSerializer(fastJsonRedisSerializer);
            template.setHashValueSerializer(fastJsonRedisSerializer);
            // key的序列化采用StringRedisSerializer
            template.setKeySerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
    
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    
    }
    View Code

    3、FastJsonRedisSerializer

    package com.sso.common.redis.shiro;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.SerializationException;
    
    import java.nio.charset.Charset;
    
    /**
     * @author yuduojia
     * @date 2018/9/14 14:42
     */
    public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    
        public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    
        private Class<T> clazz;
    
        public FastJsonRedisSerializer(Class<T> clazz) {
            super();
            this.clazz = clazz;
        }
    
        @Override
        public byte[] serialize(T t) throws SerializationException {
            if (null == t) {
                return new byte[0];
            }
            return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
        }
    
        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
            if (null == bytes || bytes.length <= 0) {
                return null;
            }
            String str = new String(bytes, DEFAULT_CHARSET);
            return (T) JSON.parseObject(str, clazz);
        }
    
    }
    View Code

    4、MyObjectInputStream

    package com.sso.common.redis.shiro;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectStreamClass;
    
    /**
     * @author yuduojia
     * @date 2018/10/6 10:20
     */
    public class MyObjectInputStream extends ObjectInputStream {
    
    
        protected MyObjectInputStream() throws IOException, SecurityException {
            super();
        }
    
        public MyObjectInputStream(InputStream arg0) throws IOException {
            super(arg0);
        }
    
        protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
            String name = desc.getName();
            try {
                if (name.endsWith("UserDO"))
                    name = "com.sso.system.domain.UserDO";
                return Class.forName(name);
    
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }
    
            return super.resolveClass(desc);
        }
    }
    View Code

    5、RedisCache

    package com.se.common.redis.shiro;
    
    /**
     * @author ydj
     * @version V1.0
     */
    
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.apache.shiro.util.CollectionUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.*;
    
    public class RedisCache<K, V> implements Cache<K, V> {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        /**
         * The wrapped Jedis instance.
         */
        @Autowired
        private RedisManager cache;
    
        /**
         * The Redis key prefix for the sessions
         */
        private String keyPrefix = "sso_redis_session:";
    
        /**
         * Returns the Redis session keys
         * prefix.
         * @return The prefix
         */
        public String getKeyPrefix() {
            return keyPrefix;
        }
    
        /**
         * Sets the Redis sessions key
         * prefix.
         * @param keyPrefix The prefix
         */
        public void setKeyPrefix(String keyPrefix) {
            this.keyPrefix = keyPrefix;
        }
    
        /**
         * 通过一个JedisManager实例构造RedisCache
         */
        public RedisCache(RedisManager cache){
            if (cache == null) {
                throw new IllegalArgumentException("Cache argument cannot be null.");
            }
            this.cache = cache;
        }
    
        /**
         * Constructs a cache instance with the specified
         * Redis manager and using a custom key prefix.
         * @param cache The cache manager instance
         * @param prefix The Redis key prefix
         */
        public RedisCache(RedisManager cache,
                          String prefix){
    
            this( cache );
    
            // set the prefix
            this.keyPrefix = prefix;
        }
    
        /**
         * 获得byte[]型的key
         * @param key
         * @return
         */
        private byte[] getByteKey(K key){
            if(key instanceof String){
                String preKey = this.keyPrefix + key;
                return preKey.getBytes();
            }else{
                return SerializeUtils.serialize(key);
            }
        }
    
        @Override
        public V get(K key) throws CacheException {
            logger.debug("根据key从Redis中获取对象 key [" + key + "]");
            try {
                if (key == null) {
                    return null;
                }else{
                    byte[] rawValue = cache.get(getByteKey(key));
                    @SuppressWarnings("unchecked")
                    V value = (V)SerializeUtils.deserialize(rawValue);
                    return value;
                }
            } catch (Throwable t) {
                throw new CacheException(t);
            }
    
        }
    
        @Override
        public V put(K key, V value) throws CacheException {
            logger.debug("根据key从存储 key [" + key + "]");
            try {
                cache.set(getByteKey(key), SerializeUtils.serialize(value));
                return value;
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
        @Override
        public V remove(K key) throws CacheException {
            logger.debug("从redis中删除 key [" + key + "]");
            try {
                V previous = get(key);
                cache.del(getByteKey(key));
                return previous;
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
        @Override
        public void clear() throws CacheException {
            logger.debug("从redis中删除所有元素");
            try {
                cache.flushDB();
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
        @Override
        public int size() {
            try {
                Long longSize = new Long(cache.dbSize());
                return longSize.intValue();
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public Set<K> keys() {
            try {
                Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
                if (CollectionUtils.isEmpty(keys)) {
                    return Collections.emptySet();
                }else{
                    Set<K> newKeys = new HashSet<K>();
                    for(byte[] key:keys){
                        newKeys.add((K)key);
                    }
                    return newKeys;
                }
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
        @Override
        public Collection<V> values() {
            try {
                Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
                if (!CollectionUtils.isEmpty(keys)) {
                    List<V> values = new ArrayList<V>(keys.size());
                    for (byte[] key : keys) {
                        @SuppressWarnings("unchecked")
                        V value = get((K)key);
                        if (value != null) {
                            values.add(value);
                        }
                    }
                    return Collections.unmodifiableList(values);
                } else {
                    return Collections.emptyList();
                }
            } catch (Throwable t) {
                throw new CacheException(t);
            }
        }
    
    }
    View Code

    6、RedisCacheManager

    package com.se.common.redis.shiro;
    
    /**
     * @author ydj
     * @version V1.0
     */
    
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.apache.shiro.cache.CacheManager;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    
    @Service
    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>();
    
        @Autowired
        private RedisManager redisManager;
    
        /**
         * The Redis key prefix for caches
         */
        private String keyPrefix = "shiro_redis_cache:";
    
        /**
         * Returns the Redis session keys
         * prefix.
         * @return The prefix
         */
        public String getKeyPrefix() {
            return keyPrefix;
        }
    
        /**
         * Sets the Redis sessions key
         * prefix.
         * @param keyPrefix The prefix
         */
        public void setKeyPrefix(String keyPrefix) {
            this.keyPrefix = keyPrefix;
        }
    
        @Override
        public <K, V> Cache<K, V> getCache(String name) throws CacheException {
            logger.debug("获取名称为: " + name + " 的RedisCache实例");
    
            Cache c = caches.get(name);
    
            if (c == null) {
    
                // initialize the Redis manager instance
                // create a new cache instance
                c = new RedisCache<K, V>(redisManager, keyPrefix);
    
                // add it to the cache collection
                caches.put(name, c);
            }
            return c;
        }
    
    //    public RedisManager getRedisManager() {
    //        return redisManager;
    //    }
    //
    //    public void setRedisManager(RedisManager redisManager) {
    //        this.redisManager = redisManager;
    //    }
    
    }
    View Code

    7、RedisManager

    package com.se.common.redis.shiro;
    
    /**
     * @author ydj
     * @version V1.0
     */
    
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisPool;
    
    import javax.annotation.Resource;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    /**
     *
     */
    @Component
    public class RedisManager {
    
        @Resource(name="P01JedisCluster")
        private JedisCluster jedis;
        private int expire = 0;
    
        public RedisManager() {
    
        }
    
        /**
         * 初始化方法
         */
    //    public void init() {
    //        if (jedisPool == null) {
    //            if (password != null && !"".equals(password)) {
    //                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
    //            } else if (timeout != 0) {
    //                jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout);
    //            } else {
    //                jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
    //            }
    //
    //        }
    //    }
    
        /**
         * get value from redis
         *
         * @param key
         * @return
         */
        public byte[] get(byte[] key) {
            byte[] value = null;
            try {
                value = jedis.get(key);
            } finally {
    
            }
            return value;
        }
    
        /**
         * set
         *
         * @param key
         * @param value
         * @return
         */
        public byte[] set(byte[] key, byte[] value) {
            try {
                jedis.set(key, value);
                if (this.expire != 0) {
                    jedis.expire(key, this.expire);
                }
            } catch (Exception e){
                e.printStackTrace();
            }
            return value;
        }
    
        /**
         * set
         *
         * @param key
         * @param value
         * @param expire
         * @return
         */
        public byte[] set(byte[] key, byte[] value, int expire) {
            try {
                jedis.set(key, value);
                if (expire != 0) {
                    jedis.expire(key, expire);
                }
            } finally {
                if (jedis != null) {
                }
            }
            return value;
        }
    
        /**
         * del
         *
         * @param key
         */
        public void del(byte[] key) {
            try {
                jedis.del(key);
            } finally {
                if (jedis != null) {
                }
            }
        }
    
        /**
         * flush
         */
        public void flushDB() {
            try {
                jedis.flushDB();
            } finally {
                if (jedis != null) {
                }
            }
        }
    
        /**
         * size
         */
        public Long dbSize() {
            Long dbSize = 0L;
            try {
                dbSize = jedis.dbSize();
            } finally {
                if (jedis != null) {
                }
            }
            return dbSize;
        }
    
        /**
         * keys
         *
         * @param regex
         * @return
         */
    //    public Set<byte[]> keys(String pattern) {
    //        Set<byte[]> keys = null;
    //        try {
    //            Jedis jedis1 = new Jedis();
    //            jedis1.keys(pattern.getBytes());
    //            keys = jedis.
    //        } finally {
    //            if (jedis != null) {
    //            }
    //        }
    //        return keys;
    //    }
    
        public Set<byte[]> keys(String pattern){
            Set<byte[]> keyss = new HashSet<byte[]>();
            Map<String, JedisPool> clusterNodes = jedis.getClusterNodes();
            for(String k : clusterNodes.keySet()){
                JedisPool jp = clusterNodes.get(k);
                Jedis connection = jp.getResource();
                try {
                    Set<String> keys1 = connection.keys(pattern);
                    Set<byte[]> key2 = new HashSet<byte[]>();
                    for(String k1 : keys1){
                        key2.add(k1.getBytes());
                    }
                    //keys.addAll(connection.keys(pattern));
                    keyss.addAll(key2);
                } catch(Exception e){
                } finally{
                    connection.close();//用完一定要close这个链接!!!
                }
            }
            return keyss;
        }
    
    //    public String getHost() {
    //        return host;
    //    }
    //
    //    public void setHost(String host) {
    //        this.host = host;
    //    }
    //
    //    public int getPort() {
    //        return port;
    //    }
    //
    //    public void setPort(int port) {
    //        this.port = port;
    //    }
    
        public int getExpire() {
            return expire;
        }
    
        public void setExpire(int expire) {
            this.expire = expire;
        }
    
    
    
    
    }
    View Code

    8、RedisSessionDAO

    package com.se.common.redis.shiro;
    
    import org.apache.shiro.session.Session;
    import org.apache.shiro.session.UnknownSessionException;
    import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.io.Serializable;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * @author ydj
     * @version V1.0
     */
    public class RedisSessionDAO extends AbstractSessionDAO {
    
        private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
        /**
         * shiro-redis的session对象前缀
         */
        @Autowired
        private RedisManager redisManager;
    
        /**
         * The Redis key prefix for the sessions
         */
        private String keyPrefix = "sso_redis_session:";
    
        @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;
            }
            redisManager.setExpire(1800);
            byte[] key = getByteKey(session.getId());
            byte[] value = SerializeUtils.serialize(session);
            session.setTimeout(redisManager.getExpire()*1000);
            this.redisManager.set(key, value, redisManager.getExpire());
        }
    
        @Override
        public void delete(Session session) {
            if(session == null || session.getId() == null){
                logger.error("session or session id is null");
                return;
            }
            redisManager.del(this.getByteKey(session.getId()));
    
        }
    
        @Override
        public Collection<Session> getActiveSessions() {
            Set<Session> sessions = new HashSet<Session>();
    
            Set<byte[]> keys = redisManager.keys(this.keyPrefix + "*");
            if(keys != null && keys.size()>0){
                for(byte[] key:keys){
                    Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
                    sessions.add(s);
                }
            }
    
            return sessions;
        }
    
        @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;
            }
    
            Session s = (Session)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
            return s;
        }
    
        /**
         * 获得byte[]型的key
         * @param key
         * @return
         */
        private byte[] getByteKey(Serializable sessionId){
            String preKey = this.keyPrefix + sessionId;
            return preKey.getBytes();
        }
    
        public RedisManager getRedisManager() {
            return redisManager;
        }
    
        public void setRedisManager(RedisManager redisManager) {
            this.redisManager = redisManager;
    
            /**
             * 初始化redisManager
             */
        }
    
        /**
         * Returns the Redis session keys
         * prefix.
         * @return The prefix
         */
        public String getKeyPrefix() {
            return keyPrefix;
        }
    
        /**
         * Sets the Redis sessions key
         * prefix.
         * @param keyPrefix The prefix
         */
        public void setKeyPrefix(String keyPrefix) {
            this.keyPrefix = keyPrefix;
        }
    
    
    }
    View Code

    9、SerializeUtils

    package com.se.common.redis.shiro;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @author ydj
     * @version V1.0
     */
    public class SerializeUtils {
    
        private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
    
        /**
         * 反序列化
         * @param bytes
         * @return
         */
        public static Object deserialize(byte[] bytes) {
    
            Object result = null;
    
            if (isEmpty(bytes)) {
                return null;
            }
    
            try {
                ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
                try {
                    ObjectInputStream objectInputStream = new MyObjectInputStream(byteStream);
                    try {
                        result = objectInputStream.readObject();
                    }
                    catch (ClassNotFoundException ex) {
                        throw new Exception("Failed to deserialize object type", ex);
                    }
                }
                catch (Throwable ex) {
                    throw new Exception("Failed to deserialize", ex);
                }
            } catch (Exception e) {
                logger.error("Failed to deserialize",e);
            }
            return result;
        }
    
        public static boolean isEmpty(byte[] data) {
            return (data == null || data.length == 0);
        }
    
        /**
         * 序列化
         * @param object
         * @return
         */
        public static byte[] serialize(Object object) {
    
            byte[] result = null;
    
            if (object == null) {
                return new byte[0];
            }
            try {
                ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
                try  {
                    if (!(object instanceof Serializable)) {
                        throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
                                "but received an object of type [" + object.getClass().getName() + "]");
                    }
                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
                    objectOutputStream.writeObject(object);
                    objectOutputStream.flush();
                    result =  byteStream.toByteArray();
                }
                catch (Throwable ex) {
                    throw new Exception("Failed to serialize", ex);
                }
            } catch (Exception ex) {
                logger.error("Failed to serialize",ex);
            }
            return result;
        }
    }
    View Code

    10、客户端StatelessSessionManager       SessionManager是在应用程序中为所有Subject提供Session的管理,包括创建,删除,失效及验证等。同其的核心组件一样,SessionManager 也是一个由SecurityManager 维护的顶级组件。 在Shiro中默认提供了一个SessionManager的实现DefaultWebSessionManager

    package com.se.common.redis.shiro;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.shiro.session.ExpiredSessionException;
    import org.apache.shiro.session.InvalidSessionException;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.session.UnknownSessionException;
    import org.apache.shiro.session.mgt.DelegatingSession;
    import org.apache.shiro.session.mgt.SessionContext;
    import org.apache.shiro.session.mgt.SessionKey;
    import org.apache.shiro.web.servlet.Cookie;
    import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
    import org.apache.shiro.web.servlet.ShiroHttpSession;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.apache.shiro.web.session.mgt.WebSessionKey;
    import org.apache.shiro.web.util.WebUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.Serializable;
    
    /**
     * @author yuduojia
     * @date 2018/9/27 10:54
     */
    @Component
    public class StatelessSessionManager extends DefaultWebSessionManager {
    
        public final static String TOKEN_NAME = "TOKEN";
    
        public final static String HEADER_TOKEN_NAME = "token";
        public final static Logger LOG = LoggerFactory.getLogger(StatelessSessionManager.class);
        private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
    
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response){
    
            String id = WebUtils.toHttp(request).getParameter(HEADER_TOKEN_NAME);
            if(StringUtils.isEmpty(id)){
                return super.getSessionId(request, response);
            }else{
                if (WebUtils.isTrue(request, "_cookie")){
                    HttpServletRequest rq = (HttpServletRequest)request;
                    HttpServletResponse rs = (HttpServletResponse)response;
                    Cookie template = getSessionIdCookie();
                    Cookie cookie = new SimpleCookie(template);
                    cookie.setValue(id);
                    cookie.saveTo(rq, rs);
                }
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);
                return id;
            }
        }
    
        private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
    
        private Cookie sessionIdCookie;
        private boolean sessionIdCookieEnabled;
    
        public StatelessSessionManager() {
            Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
            cookie.setHttpOnly(true); // more secure, protects against XSS attacks
            this.sessionIdCookie = cookie;
            this.sessionIdCookieEnabled = true;
        }
    
        public Cookie getSessionIdCookie() {
            return sessionIdCookie;
        }
    
        public void setSessionIdCookie(Cookie sessionIdCookie) {
            this.sessionIdCookie = sessionIdCookie;
        }
    
        public boolean isSessionIdCookieEnabled() {
            return sessionIdCookieEnabled;
        }
    
        public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
            this.sessionIdCookieEnabled = sessionIdCookieEnabled;
        }
    
        private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
            if (currentId == null) {
                String msg = "sessionId cannot be null when persisting for subsequent requests.";
                throw new IllegalArgumentException(msg);
            }
            Cookie template = getSessionIdCookie();
            Cookie cookie = new SimpleCookie(template);
            String idString = currentId.toString();
            cookie.setValue(idString);
            cookie.saveTo(request, response);
            log.trace("Set session ID cookie for session with id {}", idString);
        }
    
        private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
            getSessionIdCookie().removeFrom(request, response);
        }
    
        private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
            if (!isSessionIdCookieEnabled()) {
                log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
                return null;
            }
            if (!(request instanceof HttpServletRequest)) {
                log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie.  Returning null.");
                return null;
            }
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
        }
    
        private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
    
            String id = getSessionIdCookieValue(request, response);
            if (id != null) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                        ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
            } else {
                // not in a cookie, or cookie is disabled - try the request URI as a
                // fallback (i.e. due to URL rewriting):
    
                // try the URI path segment parameters first:
                id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
    
                if (id == null) {
                    // not a URI path segment parameter, try the query parameters:
                    String name = getSessionIdName();
                    id = request.getParameter(name);
                    if (id == null) {
                        // try lowercase:
                        id = request.getParameter(name.toLowerCase());
                    }
                }
                if (id != null) {
                    request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                            ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
                }
            }
            if (id != null) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
                // automatically mark it valid here. If it is invalid, the
                // onUnknownSession method below will be invoked and we'll remove
                // the attribute at that time.
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            }
            return id;
        }
    
        // SHIRO-351
        // also see
        // http://cdivilly.wordpress.com/2011/04/22/java-servlets-uri-parameters/
        // since 1.2.2
        private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {
    
            if (!(servletRequest instanceof HttpServletRequest)) {
                return null;
            }
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String uri = request.getRequestURI();
            if (uri == null) {
                return null;
            }
    
            int queryStartIndex = uri.indexOf('?');
            if (queryStartIndex >= 0) { // get rid of the query string
                uri = uri.substring(0, queryStartIndex);
            }
    
            int index = uri.indexOf(';'); // now check for path segment parameters:
            if (index < 0) {
                // no path segment params - return:
                return null;
            }
    
            // there are path segment params, let's get the last one that may exist:
    
            final String TOKEN = paramName + "=";
    
            uri = uri.substring(index + 1); // uri now contains only the path
            // segment params
    
            // we only care about the last JSESSIONID param:
            index = uri.lastIndexOf(TOKEN);
            if (index < 0) {
                // no segment param:
                return null;
            }
    
            uri = uri.substring(index + TOKEN.length());
    
            index = uri.indexOf(';'); // strip off any remaining segment params:
            if (index >= 0) {
                uri = uri.substring(0, index);
            }
    
            return uri; // what remains is the value
        }
    
        //------------------------------------------------------------------------------------------------------------------
        /**
         * Modify By Goma
         */
        @Override
        protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
            Serializable sessionId = getSessionId(sessionKey);
            if (sessionId == null) {
                log.debug("Unable to resolve session ID from SessionKey [{}].  Returning null to indicate a "
                        + "session could not be found.", sessionKey);
                return null;
            }
    
    
            // ***************Add By Goma****************
            ServletRequest request = null;
            if (sessionKey instanceof WebSessionKey) {
                request = ((WebSessionKey) sessionKey).getServletRequest();
            }
    
            if (request != null) {
                Object s = request.getAttribute(sessionId.toString());
                if (s != null) {
                    return (Session) s;
                }
            }
            // ***************Add By Goma****************
    
    
            Session s = retrieveSessionFromDataSource(sessionId);
            if (s == null) {
                // session ID was provided, meaning one is expected to be found, but
                // we couldn't find one:
                String msg = "Could not find session with ID [" + sessionId + "]";
                throw new UnknownSessionException(msg);
            }
    
    
    
            // ***************Add By Goma****************
            if (request != null) {
                request.setAttribute(sessionId.toString(),s);
            }
            // ***************Add By Goma****************
    
    
            return s;
        }
        //------------------------------------------------------------------------------------------------------------------
    
        // since 1.2.1
        private String getSessionIdName() {
            String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
            if (name == null) {
                name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
            }
            return name;
        }
    
        protected Session createExposedSession(Session session, SessionContext context) {
            if (!WebUtils.isWeb(context)) {
                return super.createExposedSession(session, context);
            }
            ServletRequest request = WebUtils.getRequest(context);
            ServletResponse response = WebUtils.getResponse(context);
            SessionKey key = new WebSessionKey(session.getId(), request, response);
            return new DelegatingSession(this, key);
        }
    
        protected Session createExposedSession(Session session, SessionKey key) {
            if (!WebUtils.isWeb(key)) {
                return super.createExposedSession(session, key);
            }
    
            ServletRequest request = WebUtils.getRequest(key);
            ServletResponse response = WebUtils.getResponse(key);
            SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
            return new DelegatingSession(this, sessionKey);
        }
    
        /**
         * Stores the Session's ID, usually as a Cookie, to associate with future
         * requests.
         *
         * @param session
         *            the session that was just {@link #createSession created}.
         */
        @Override
        protected void onStart(Session session, SessionContext context) {
            super.onStart(session, context);
    
            if (!WebUtils.isHttp(context)) {
                log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response "
                        + "pair. No session ID cookie will be set.");
                return;
    
            }
            HttpServletRequest request = WebUtils.getHttpRequest(context);
            HttpServletResponse response = WebUtils.getHttpResponse(context);
    
            if (isSessionIdCookieEnabled()) {
                Serializable sessionId = session.getId();
                storeSessionId(sessionId, request, response);
            } else {
                log.debug("Session ID cookie is disabled.  No cookie has been set for new session with id {}",
                        session.getId());
            }
    
            request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
        }
    
        @Override
        public Serializable getSessionId(SessionKey key) {
            Serializable id = super.getSessionId(key);
            if (id == null && WebUtils.isWeb(key)) {
                ServletRequest request = WebUtils.getRequest(key);
                ServletResponse response = WebUtils.getResponse(key);
                id = getSessionId(request, response);
            }
            return id;
        }
    
        /*protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            return getReferencedSessionId(request, response);
        }*/
    
        @Override
        protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
            super.onExpiration(s, ese, key);
            onInvalidation(key);
        }
    
        @Override
        protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
            super.onInvalidation(session, ise, key);
            onInvalidation(key);
        }
    
        private void onInvalidation(SessionKey key) {
            ServletRequest request = WebUtils.getRequest(key);
            if (request != null) {
                request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
            }
            if (WebUtils.isHttp(key)) {
                log.debug("Referenced session was invalid.  Removing session ID cookie.");
                removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
            } else {
                log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response "
                        + "pair. Session ID cookie will not be removed due to invalidated session.");
            }
        }
    
        @Override
        protected void onStop(Session session, SessionKey key) {
            super.onStop(session, key);
            if (WebUtils.isHttp(key)) {
                HttpServletRequest request = WebUtils.getHttpRequest(key);
                HttpServletResponse response = WebUtils.getHttpResponse(key);
                log.debug("Session has been stopped (subject logout or explicit stop).  Removing session ID cookie.");
                removeSessionIdCookie(request, response);
            } else {
                log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response "
                        + "pair. Session ID cookie will not be removed due to stopped session.");
            }
        }
    
        /**
         * This is a native session manager implementation, so this method returns
         * {@code false} always.
         *
         * @return {@code false} always
         * @since 1.2
         */
        public boolean isServletContainerSessions() {
            return false;
        }
    
    
    }
    View Code

    DefaultWebSessionManager类    介绍  不是项目用到的

    DefaultWebSessionManager类
    1.数据属性
    
    private Cookie sessionIdCookie;//sessionId cookie
    private boolean sessionIdCookieEnabled;//session是否可以被保存到cookie中
    
    2.构造方法
    
    public DefaultWebSessionManager() {
            Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
            cookie.setHttpOnly(true); //more secure, protects against XSS attacks
            this.sessionIdCookie = cookie;
            this.sessionIdCookieEnabled = true;
    }
    
    3.获取sessionIdCookie
    
    public Cookie getSessionIdCookie() {
            return sessionIdCookie;
    }
    
    4.设置sessionIdCookie
    
    public void setSessionIdCookie(Cookie sessionIdCookie) {
            this.sessionIdCookie = sessionIdCookie;
    }
    
    5.是否将sessionId存储到cookie中
    
    public boolean isSessionIdCookieEnabled() {
            return sessionIdCookieEnabled;
    }
    
    6.设置是否将sessionId存储到cookie中
    
    public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
            this.sessionIdCookieEnabled = sessionIdCookieEnabled;
    }
    
    7.存储sessionId到cookie中
    
    private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
            if (currentId == null) {
                String msg = "sessionId cannot be null when persisting for subsequent requests.";
                throw new IllegalArgumentException(msg);
            }
            Cookie template = getSessionIdCookie();
            Cookie cookie = new SimpleCookie(template);
            String idString = currentId.toString();
            cookie.setValue(idString);
            cookie.saveTo(request, response);
            log.trace("Set session ID cookie for session with id {}", idString);
        }
    
    8.从cookie中移除session信息
    
    private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
            getSessionIdCookie().removeFrom(request, response);
    }
    
    9.从cookie中读取sessionId信息
    
    private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
            if (!isSessionIdCookieEnabled()) {
                log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
                return null;
            }
            if (!(request instanceof HttpServletRequest)) {
                log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie.  Returning null.");
                return null;
            }
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
        }
    
    10.检测sessionId关联源(如果可以从cookie中获取sessionId,则在request中设置sessionId的关联源为cookie;如果不可以读取,则从request访问路径中获取,如果不存在,则从request的parameter中获取,如果从request的访问路径中或者parameter中获取到的不为空,则设置关联源为url;并在将sessionId和合法信息存储到request中)
    
    private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
    
            String id = getSessionIdCookieValue(request, response);
            if (id != null) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                        ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
            } else {
                //not in a cookie, or cookie is disabled - try the request URI as a fallback (i.e. due to URL rewriting):
    
                //try the URI path segment parameters first:
                id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
    
                if (id == null) {
                    //not a URI path segment parameter, try the query parameters:
                    String name = getSessionIdName();
                    id = request.getParameter(name);
                    if (id == null) {
                        //try lowercase:
                        id = request.getParameter(name.toLowerCase());
                    }
                }
                if (id != null) {
                    request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                            ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
                }
            }
            if (id != null) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
                //automatically mark it valid here.  If it is invalid, the
                //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            }
            return id;
        }
    
    11.从request路径中获取sessionId信息
    
    private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {
    
            if (!(servletRequest instanceof HttpServletRequest)) {
                return null;
            }
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            String uri = request.getRequestURI();
            if (uri == null) {
                return null;
            }
    
            int queryStartIndex = uri.indexOf('?');
            if (queryStartIndex >= 0) { //get rid of the query string
                uri = uri.substring(0, queryStartIndex);
            }
    
            int index = uri.indexOf(';'); //now check for path segment parameters:
            if (index < 0) {
                //no path segment params - return:
                return null;
            }
    
            //there are path segment params, let's get the last one that may exist:
    
            final String TOKEN = paramName + "=";
    
            uri = uri.substring(index+1); //uri now contains only the path segment params
    
            //we only care about the last JSESSIONID param:
            index = uri.lastIndexOf(TOKEN);
            if (index < 0) {
                //no segment param:
                return null;
            }
    
            uri = uri.substring(index + TOKEN.length());
    
            index = uri.indexOf(';'); //strip off any remaining segment params:
            if(index >= 0) {
                uri = uri.substring(0, index);
            }
    
            return uri; //what remains is the value
        }
    
    12.获取sessionId名字
    
    private String getSessionIdName() {
            String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
            if (name == null) {
                name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
            }
            return name;
        }
    
    13.创建session信息(它覆盖了AbstractNativeSessionManager接口的方法)
    
    protected Session createExposedSession(Session session, SessionContext context) {
            if (!WebUtils.isWeb(context)) {
                return super.createExposedSession(session, context);
            }
            ServletRequest request = WebUtils.getRequest(context);
            ServletResponse response = WebUtils.getResponse(context);
            SessionKey key = new WebSessionKey(session.getId(), request, response);
            return new DelegatingSession(this, key);
        }
    
    14.创建session信息(它覆盖了AbstractNativeSessionManager抽象类的方法)
    
    protected Session createExposedSession(Session session, SessionKey key) {
            if (!WebUtils.isWeb(key)) {
                return super.createExposedSession(session, key);
            }
    
            ServletRequest request = WebUtils.getRequest(key);
            ServletResponse response = WebUtils.getResponse(key);
            SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
            return new DelegatingSession(this, sessionKey);
        }
    
    15.启动session(将session存储到cookie中,并将cookie中移除session源,设置session是新的,它覆盖了AbstractNativeSessionManager抽象类的方法)
    
    protected void onStart(Session session, SessionContext context) {
            super.onStart(session, context);
    
            if (!WebUtils.isHttp(context)) {
                log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +
                        "pair. No session ID cookie will be set.");
                return;
    
            }
            HttpServletRequest request = WebUtils.getHttpRequest(context);
            HttpServletResponse response = WebUtils.getHttpResponse(context);
    
            if (isSessionIdCookieEnabled()) {
                Serializable sessionId = session.getId();
                storeSessionId(sessionId, request, response);
            } else {
                log.debug("Session ID cookie is disabled.  No cookie has been set for new session with id {}", session.getId());
            }
    
            request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
        }
    
    16.获取sessionId(先从sessionKey中获取,如果没有,则从cookie中获取,如果在没有,则从request请求路径或者parameter中获取,它覆盖了DefaultSessionManager类的方法)
    
    public Serializable getSessionId(SessionKey key) {
            Serializable id = super.getSessionId(key);
            if (id == null && WebUtils.isWeb(key)) {
                ServletRequest request = WebUtils.getRequest(key);
                ServletResponse response = WebUtils.getResponse(key);
                id = getSessionId(request, response);
            }
            return id;
        }
    
    17.从cookie或者request中获取sessionId信息
    
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            return getReferencedSessionId(request, response);
    }
    
    18.session过期(它覆盖了AbstractValidatingSessionManager抽象类的方法)
    
    protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
            super.onExpiration(s, ese, key);
            onInvalidation(key);
    }
    
    19.session失效(它覆盖了AbstractValidatingSessionManager抽象类的方法)
    
    protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
            super.onInvalidation(session, ise, key);
            onInvalidation(key);
        }
    
    20.移除request中属性(sessionId是合法的和从cookie中移除sessionId)
    
    private void onInvalidation(SessionKey key) {
            ServletRequest request = WebUtils.getRequest(key);
            if (request != null) {
                request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
            }
            if (WebUtils.isHttp(key)) {
                log.debug("Referenced session was invalid.  Removing session ID cookie.");
                removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
            } else {
                log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
                        "pair. Session ID cookie will not be removed due to invalidated session.");
            }
        }
    21.暂停session(设置session的暂停时间,并从cookie中移除session,它实现了AbstractNativeSessionManager抽象类的方法)
    
    protected void onStop(Session session, SessionKey key) {
            super.onStop(session, key);
            if (WebUtils.isHttp(key)) {
                HttpServletRequest request = WebUtils.getHttpRequest(key);
                HttpServletResponse response = WebUtils.getHttpResponse(key);
                log.debug("Session has been stopped (subject logout or explicit stop).  Removing session ID cookie.");
                removeSessionIdCookie(request, response);
            } else {
                log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
                        "pair. Session ID cookie will not be removed due to stopped session.");
            }
        }
    
    22.如果session被servlet container管理则返回true;如果被shiro管理,则返回false
    
    public boolean isServletContainerSessions() {
            return false;
    }

    11、客户端ShiroConfig           设置DefaultWebSessionManager

    package com.se.system.config;
    
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    import com.se.common.config.Constant;
    import com.se.common.redis.shiro.RedisCacheManager;
    import com.se.common.redis.shiro.RedisManager;
    import com.se.common.redis.shiro.RedisSessionDAO;
    import com.se.common.redis.shiro.StatelessSessionManager;
    import com.se.system.shiro.UserRealm;
    //import org.apache.shiro.cache.CacheManager;
    import net.sf.ehcache.CacheManager;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.SessionListener;
    import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
    import org.apache.shiro.session.mgt.eis.SessionDAO;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.ehcache.EhCacheCacheManager;
    import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    
    /**
     * @author ydj
     */
    @Configuration
    public class ShiroConfig {
    //    @Value("${spring.redis.host}")
    //    private String host;
    //    @Value("${spring.redis.password}")
    //    private String password;
    //    @Value("${spring.redis.port}")
    //    private int port;
    //    @Value("${spring.redis.timeout}")
    //    private int timeout;
    
        @Value("${spring.cache.type}")
        private String cacheType;
    
        @Value("${server.session-timeout}")
        private int tomcatTimeout;
    
        @Bean
        public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
        @Autowired
        private RedisManager redisManager;
    
        @Autowired
        private RedisCacheManager cacheManager;
        /**
         * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
         *
         * @return
         */
        @Bean
        public ShiroDialect shiroDialect() {
            return new ShiroDialect();
        }
    
        @Bean
        ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("/login");
            shiroFilterFactoryBean.setSuccessUrl("/index");
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            //对位提供服务接口忽略
            filterChainDefinitionMap.put("/ssoGetUserIdList/**", "anon");
            filterChainDefinitionMap.put("/sendEmail/**", "anon");
            filterChainDefinitionMap.put("/YPObtainSMSState/YPobtainSMSState", "anon");
            filterChainDefinitionMap.put("/HKsendSMS/**", "anon");
            filterChainDefinitionMap.put("/sendSMS/**", "anon");
            filterChainDefinitionMap.put("/batchSendSMS/**", "anon");
            filterChainDefinitionMap.put("/yimeicmq/**", "anon");
            filterChainDefinitionMap.put("/cslcmq/**", "anon");
            filterChainDefinitionMap.put("/yunpiancmq/**", "anon");
            filterChainDefinitionMap.put("/cmqtest/**", "anon");
            filterChainDefinitionMap.put("/asyncSendEmail/**", "anon");
            filterChainDefinitionMap.put("/asyncSendSMS/**", "anon");
            filterChainDefinitionMap.put("/oneSMSCmq/**", "anon");
            filterChainDefinitionMap.put("/emailCmq/**", "anon");
            filterChainDefinitionMap.put("/batchBackReceiver/**", "anon");
            filterChainDefinitionMap.put("/Timescheduling/**", "anon");  //亿美时间调度获取短信状态报告
            filterChainDefinitionMap.put("/statueReport/**", "anon");  //香港获取推送状态报告的接口
            filterChainDefinitionMap.put("/sys/userpush/**", "anon");  //角色操作接口
            filterChainDefinitionMap.put("/sys/rolepush/**", "anon");  //角色操作接口
    
    
            filterChainDefinitionMap.put("/login","anon");
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/fonts/**", "anon");
            filterChainDefinitionMap.put("/img/**", "anon");
            filterChainDefinitionMap.put("/docs/**", "anon");
            filterChainDefinitionMap.put("/druid/**", "anon");
            filterChainDefinitionMap.put("/upload/**", "anon");
            filterChainDefinitionMap.put("/files/**", "anon");
            filterChainDefinitionMap.put("/templates/*", "anon");
            filterChainDefinitionMap.put("/logout", "logout");
            filterChainDefinitionMap.put("/", "anon");
            filterChainDefinitionMap.put("/blog", "anon");
            filterChainDefinitionMap.put("/blog/open/**", "anon");
            filterChainDefinitionMap.put("/**", "user");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
    
        @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //设置realm.
            securityManager.setRealm(userRealm());
            // 自定义缓存实现 使用redis
            if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
                securityManager.setCacheManager(cacheManager);
            } else {
                securityManager.setCacheManager(ehCacheManager());
            }
           // securityManager.setCacheManager(cacheManager);
            securityManager.setSessionManager(sessionManager());
            return securityManager;
        }
    
        @Bean
        UserRealm userRealm() {
            UserRealm userRealm = new UserRealm();
            return userRealm;
        }
    
        /**
         * 开启shiro aop注解支持.
         * 使用代理方式;所以需要开启代码支持;
         *
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        /**
         * 配置shiro redisManager
         *
         * @return
         */
    //    @Bean
    //    public RedisManager redisManager() {
    //        RedisManager redisManager = new RedisManager();
    //        redisManager.setHost(host);
    //        redisManager.setPort(port);
    //        redisManager.setExpire(1800);// 配置缓存过期时间
    //        //redisManager.setTimeout(1800);
    //        redisManager.setPassword(password);
    //        return redisManager;
    //    }
    
        /**
         * cacheManager 缓存 redis实现
         * 使用的是shiro-redis开源插件
         *
         * @return
         */
    //    public RedisCacheManager cacheManager() {
    //        RedisCacheManager redisCacheManager = new RedisCacheManager();
    //        redisCacheManager.setRedisManager(redisManager());
    //        return redisCacheManager;
    //    }
    
    
        /**
         * RedisSessionDAO shiro sessionDao层的实现 通过redis
         * 使用的是shiro-redis开源插件
         */
        @Bean
        public RedisSessionDAO redisSessionDAO() {
            RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
            redisSessionDAO.setRedisManager(redisManager);
            return redisSessionDAO;
        }
    
        @Bean
        public SessionDAO sessionDAO() {
            if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
                return redisSessionDAO();
            } else {
                return new MemorySessionDAO();
            }
           // return redisSessionDAO();
        }
    
        /**
         * shiro session的管理
         */
        @Bean
        public DefaultWebSessionManager sessionManager() {
            DefaultWebSessionManager sessionManager = new StatelessSessionManager();
            sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000);
            sessionManager.setSessionDAO(sessionDAO());
            Collection<SessionListener> listeners = new ArrayList<SessionListener>();
            listeners.add(new BDSessionListener());
            sessionManager.setSessionListeners(listeners);
            return sessionManager;
        }
    
        @Bean
        public EhCacheManager ehCacheManager() {
            EhCacheManager em = new EhCacheManager();
            em.setCacheManager(CacheManager.create());
            return em;
        }
    
    
    }
    View Code

    12、服务端ShiroCofig             设置双Realm 

    package com.sso.system.config;
    
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    import com.sso.common.config.Constant;
    import com.sso.common.redis.shiro.RedisCacheManager;
    import com.sso.common.redis.shiro.RedisManager;
    import com.sso.common.redis.shiro.RedisSessionDAO;
    import com.sso.system.shiro.ChildrenRealm;
    import com.sso.system.shiro.UserModularRealmAuthenticator;
    import com.sso.system.shiro.UserRealm;
    //import org.apache.shiro.cache.CacheManager;
    import net.sf.ehcache.CacheManager;
    import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
    import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.realm.Realm;
    import org.apache.shiro.session.SessionListener;
    import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
    import org.apache.shiro.session.mgt.eis.SessionDAO;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.ehcache.EhCacheCacheManager;
    import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    import java.util.List;
    
    /**
     * @author ydj
     */
    @Configuration
    public class ShiroConfig {
    //    @Value("${spring.redis.host}")
    //    private String host;
    //    @Value("${spring.redis.password}")
    //    private String password;
    //    @Value("${spring.redis.port}")
    //    private int port;
    //    @Value("${spring.redis.timeout}")
    //    private int timeout;
    
    //    @Value("${spring.cache.type}")
    //    private String cacheType;
    
        @Value("${server.session-timeout}")
        private int tomcatTimeout;
    
        @Bean
        public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
        @Autowired
        private RedisManager redisManager;
    
        @Autowired
        private RedisCacheManager cacheManager;
        /**
         * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
         *
         * @return
         */
        @Bean
        public ShiroDialect shiroDialect() {
            return new ShiroDialect();
        }
    
        @Bean
        ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("/login");
            shiroFilterFactoryBean.setLoginUrl("/childrenLogin");//
            shiroFilterFactoryBean.setSuccessUrl("/index");
            shiroFilterFactoryBean.setSuccessUrl("/childIndex");//
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            //对位提供服务接口忽略
    
            filterChainDefinitionMap.put("/login","anon");
            filterChainDefinitionMap.put("/childrenLogin","anon");
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/fonts/**", "anon");
            filterChainDefinitionMap.put("/img/**", "anon");
            filterChainDefinitionMap.put("/docs/**", "anon");
            filterChainDefinitionMap.put("/druid/**", "anon");
            filterChainDefinitionMap.put("/upload/**", "anon");
            filterChainDefinitionMap.put("/files/**", "anon");
            filterChainDefinitionMap.put("/templates/*", "anon");
            filterChainDefinitionMap.put("/logout", "logout");
            filterChainDefinitionMap.put("/", "anon");
            filterChainDefinitionMap.put("/blog", "anon");
            filterChainDefinitionMap.put("/blog/open/**", "anon");
            filterChainDefinitionMap.put("/**", "authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
    
        @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //设置realm.
            securityManager.setAuthenticator(modularRealmAuthenticator());
            List<Realm> realms = new ArrayList<>();
            //添加多个Realm
            realms.add(userRealm());
            realms.add(childrenRealm());
            securityManager.setRealms(realms);
            // 自定义缓存实现 使用redis
            /*if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
                securityManager.setCacheManager(cacheManager);
            } else {
                securityManager.setCacheManager(ehCacheManager());
            }*/
            securityManager.setCacheManager(cacheManager);
            securityManager.setSessionManager(sessionManager());
            return securityManager;
        }
    
    
        @Bean
        public ChildrenRealm childrenRealm() {
            ChildrenRealm childrenRealm = new ChildrenRealm();
            return childrenRealm;
        }
    
        @Bean
        public ModularRealmAuthenticator modularRealmAuthenticator(){
            //自己重写的ModularRealmAuthenticator
            UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
            modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
            return modularRealmAuthenticator;
        }
    
        @Bean
        UserRealm userRealm() {
            UserRealm userRealm = new UserRealm();
            return userRealm;
        }
    
        /**
         * 开启shiro aop注解支持.
         * 使用代理方式;所以需要开启代码支持;
         *
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        /**
         * 配置shiro redisManager
         *
         * @return
         */
    //    @Bean
    //    public RedisManager redisManager() {
    //        RedisManager redisManager = new RedisManager();
    //        redisManager.setHost(host);
    //        redisManager.setPort(port);
    //        redisManager.setExpire(1800);// 配置缓存过期时间
    //        //redisManager.setTimeout(1800);
    //        redisManager.setPassword(password);
    //        return redisManager;
    //    }
    
        /**
         * cacheManager 缓存 redis实现
         * 使用的是shiro-redis开源插件
         *
         * @return
         */
    //    public RedisCacheManager cacheManager() {
    //        RedisCacheManager redisCacheManager = new RedisCacheManager();
    //        redisCacheManager.setRedisManager(redisManager());
    //        return redisCacheManager;
    //    }
    
    
        /**
         * RedisSessionDAO shiro sessionDao层的实现 通过redis
         * 使用的是shiro-redis开源插件
         */
        @Bean
        public RedisSessionDAO redisSessionDAO() {
            RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
            redisSessionDAO.setRedisManager(redisManager);
            return redisSessionDAO;
        }
    
        @Bean
        public SessionDAO sessionDAO() {
            /*if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
                return redisSessionDAO();
            } else {
                return new MemorySessionDAO();
            }*/
            return redisSessionDAO();
        }
    
        /**
         * shiro session的管理
         */
        @Bean
        public DefaultWebSessionManager sessionManager() {
            DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
            sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000);
            sessionManager.setSessionDAO(sessionDAO());
            Collection<SessionListener> listeners = new ArrayList<SessionListener>();
            listeners.add(new BDSessionListener());
            sessionManager.setSessionListeners(listeners);
            //sessionManager.setSessionIdCookie(sessionIdCookie());
            return sessionManager;
        }
    
        @Bean
        public EhCacheManager ehCacheManager() {
            EhCacheManager em = new EhCacheManager();
            em.setCacheManager(CacheManager.create());
            return em;
        }
    
       /* @Bean
        public SimpleCookie sessionIdCookie() {
            SimpleCookie cookie = new SimpleCookie();
            cookie.setName("SSOSESSIONID");
            cookie.setHttpOnly(true);
            cookie.setMaxAge(18000);
            return cookie;
        }*/
    
    
    
    }
    View Code

    二、登录,验证,并且双身份用户Realm (服务端)  ChildrenRealm是普通用户登录,UserRealm系统管理员用户登录   所以这个设计是有两个登录页面

    1、LoginController

    package com.sso.system.controller;
    
    import com.sso.common.annotation.Log;
    import com.sso.common.controller.BaseController;
    import com.sso.common.domain.FileDO;
    import com.sso.common.domain.Tree;
    import com.sso.common.service.FileService;
    import com.sso.common.utils.MD5Utils;
    import com.sso.common.utils.R;
    import com.sso.common.utils.ShiroUtils;
    import com.sso.system.domain.MenuDO;
    import com.sso.system.service.MenuService;
    import com.sso.system.shiro.UserToken;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.List;
    
    @Controller
    public class LoginController extends BaseController {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        MenuService menuService;
        @Autowired
        FileService fileService;
        @GetMapping({ "/", "" })
        String welcome(Model model) {
    
            return "redirect:/login";
        }
    
        @Log("请求访问主页")
        @GetMapping({ "/index" })
        String index(Model model) {
            List<Tree<MenuDO>> menus = menuService.listMenuTree(getUserId());
            model.addAttribute("menus", menus);
            model.addAttribute("name", getUser().getName());
            FileDO fileDO = fileService.get(getUser().getPicId());
            if(fileDO!=null&&fileDO.getUrl()!=null){
                if(fileService.isExist(fileDO.getUrl())){
                    model.addAttribute("picUrl",fileDO.getUrl());
                }else {
                    model.addAttribute("picUrl","/img/photo_s.jpg");
                }
            }else {
                model.addAttribute("picUrl","/img/photo_s.jpg");
            }
            model.addAttribute("username", getUser().getUsername());
            return "index_v1";
        }
    
        @GetMapping("/login")
        String login() {
            return "login";
        }
    
        @Log("登录")
        @PostMapping("/login")
        @ResponseBody
        R ajaxLogin(String username, String password) {
    
            password = MD5Utils.encrypt(username, password);
            UserToken token = new UserToken(username, password,"User");
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(token);
                return R.ok();
            }catch (UnknownAccountException e) {
                return R.error("账户不存在");
            }catch (IncorrectCredentialsException e) {
                return R.error("密码错误");
            }
        }
    
        @GetMapping("/logout")
        String logout() {
            ShiroUtils.logout();
            return "redirect:/login";
        }
    
        @GetMapping("/main")
        String main() {
            return "main";
        }
    
    }
    View Code

    2、ChildrenRealm  这个是客户登录   Realm提供了安全的访问应用的相关实体类,比如用户、角色、权限,对其中的访问应用相应的认证或者授权操作。其提供的主要的方法为AuthenticationInfo#getAuthenticationInfo,涉及的内容是关于信息的认证,这主要由AuthencatingRealm类实现

    package com.sso.system.controller;
    
    import com.sso.common.annotation.Log;
    import com.sso.common.controller.BaseController;
    import com.sso.common.domain.FileDO;
    import com.sso.common.domain.Tree;
    import com.sso.common.service.FileService;
    import com.sso.common.utils.MD5Utils;
    import com.sso.common.utils.R;
    import com.sso.common.utils.ShiroUtils;
    import com.sso.system.domain.MenuDO;
    import com.sso.system.service.MenuService;
    import com.sso.system.shiro.UserToken;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.List;
    
    @Controller
    public class LoginController extends BaseController {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        MenuService menuService;
        @Autowired
        FileService fileService;
        @GetMapping({ "/", "" })
        String welcome(Model model) {
    
            return "redirect:/login";
        }
    
        @Log("请求访问主页")
        @GetMapping({ "/index" })
        String index(Model model) {
            List<Tree<MenuDO>> menus = menuService.listMenuTree(getUserId());
            model.addAttribute("menus", menus);
            model.addAttribute("name", getUser().getName());
            FileDO fileDO = fileService.get(getUser().getPicId());
            if(fileDO!=null&&fileDO.getUrl()!=null){
                if(fileService.isExist(fileDO.getUrl())){
                    model.addAttribute("picUrl",fileDO.getUrl());
                }else {
                    model.addAttribute("picUrl","/img/photo_s.jpg");
                }
            }else {
                model.addAttribute("picUrl","/img/photo_s.jpg");
            }
            model.addAttribute("username", getUser().getUsername());
            return "index_v1";
        }
    
        @GetMapping("/login")
        String login() {
            return "login";
        }
    
        @Log("登录")
        @PostMapping("/login")
        @ResponseBody
        R ajaxLogin(String username, String password) {
    
            password = MD5Utils.encrypt(username, password);
            UserToken token = new UserToken(username, password,"User");
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(token);
                return R.ok();
            }catch (UnknownAccountException e) {
                return R.error("账户不存在");
            }catch (IncorrectCredentialsException e) {
                return R.error("密码错误");
            }
        }
    
        @GetMapping("/logout")
        String logout() {
            ShiroUtils.logout();
            return "redirect:/login";
        }
    
        @GetMapping("/main")
        String main() {
            return "main";
        }
    
    }
    View Code

    3、UserRealm 这个是系统管理员登录的 

    package com.sso.system.shiro;
    
    import com.sso.common.config.ApplicationContextRegister;
    import com.sso.common.utils.ShiroUtils;
    import com.sso.system.dao.UserDao;
    import com.sso.system.domain.UserDO;
    import com.sso.system.service.MenuService;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class UserRealm extends AuthorizingRealm {
    /*    @Autowired
        UserDao userMapper;
        @Autowired
        MenuService menuService;*/
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
            Long userId = ShiroUtils.getUserId();
            MenuService menuService = ApplicationContextRegister.getBean(MenuService.class);
            Set<String> perms = menuService.listPerms(userId);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.setStringPermissions(perms);
            return info;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String username = (String) token.getPrincipal();
            Map<String, Object> map = new HashMap<>(16);
            map.put("username", username);
            String password = new String((char[]) token.getCredentials());
    
            UserDao userMapper = ApplicationContextRegister.getBean(UserDao.class);
            // 查询用户信息
            List<UserDO> userDOS = userMapper.list(map);
            UserDO user = null;
            if(userDOS.size()>0){
                user=userDOS.get(0);
            }
    
            // 账号不存在
            if (user == null) {
                throw new UnknownAccountException("账号或密码不正确");
            }
    
            // 密码错误
            if (!password.equals(user.getPassword())) {
                throw new IncorrectCredentialsException("账号或密码不正确");
            }
    
            // 账号锁定
            if (user.getStatus() == 0) {
                throw new LockedAccountException("账号已被锁定,请联系管理员");
            }
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
            return info;
        }
    
    }
    View Code

    4、UserModularRealmAuthenticator

    package com.sso.system.shiro;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
    import org.apache.shiro.realm.Realm;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.ArrayList;
    import java.util.Collection;
    
    /**
     * @author yuduojia
     * @date 2018/10/9 19:51
     */
    public class UserModularRealmAuthenticator extends ModularRealmAuthenticator {
    
        private static final Logger logger = LoggerFactory.getLogger(UserModularRealmAuthenticator.class);
    
        @Override
        protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
                throws AuthenticationException {
            logger.info("UserModularRealmAuthenticator:method doAuthenticate() execute ");
            // 判断getRealms()是否返回为空
            assertRealmsConfigured();
            // 强制转换回自定义的CustomizedToken
            UserToken userToken = (UserToken) authenticationToken;
            // 登录类型
            String loginType = userToken.getLoginType();
            // 所有Realm
            Collection<Realm> realms = getRealms();
            // 登录类型对应的所有Realm
            Collection<Realm> typeRealms = new ArrayList<>();
    
            for (Realm realm : realms) {
                if (realm.getName().contains(loginType))
                typeRealms.add(realm);
            }
    
            // 判断是单Realm还是多Realm
            if (typeRealms.size() == 1){
                logger.info("doSingleRealmAuthentication() execute ");
                return doSingleRealmAuthentication(typeRealms.iterator().next(), userToken);
            }
            else{
                logger.info("doMultiRealmAuthentication() execute ");
                return doMultiRealmAuthentication(typeRealms, userToken);
            }
        }
    
    
    
    }
    View Code

    5、LoginType

    package com.sso.system.shiro;
    
    /**
     * @author
     * @version 1.0
     * @date 2018/10/9
     */
    public enum LoginType {
    
        CHILDREN("Children"),  ADMIN("User");
    
        private String type;
    
        private LoginType(String type) {
            this.type = type;
        }
    
        @Override
        public String toString() {
            return this.type.toString();
        }
    
    
    }
    View Code

    6、UserToken

    package com.sso.system.shiro;
    
    import org.apache.shiro.authc.UsernamePasswordToken;
    
    /**
     * @author yuduojia
     * @date 2018/10/9 19:49
     */
    public class UserToken extends UsernamePasswordToken {
        //登录类型,判断是普通用户还是系统管理员用户登录
        private String loginType;
    
        public UserToken(final String username, final String password,String loginType) {
            super(username,password);
            this.loginType = loginType;
        }
    
        public String getLoginType() {
            return loginType;
        }
        public void setLoginType(String loginType) {
            this.loginType = loginType;
        }
    
    }
    View Code

    7、ChildLoginController

    package com.sso.children.controller;
    
    import com.google.gson.Gson;
    import com.sso.children.domain.ChildDeptDO;
    import com.sso.children.domain.ChildMenuDO;
    import com.sso.children.domain.OfficeDO;
    import com.sso.children.service.ChildDeptService;
    import com.sso.children.service.ChildMenuService;
    import com.sso.children.service.ChildUserService;
    import com.sso.children.service.UserOfficeService;
    import com.sso.children.util.OfficeToZtree;
    import com.sso.children.vo.ChildDeptVO;
    import com.sso.children.vo.ZtreeVO;
    import com.sso.common.annotation.Log;
    import com.sso.common.controller.BaseController;
    import com.sso.common.domain.Tree;
    import com.sso.common.service.FileService;
    import com.sso.common.utils.MD5Utils;
    import com.sso.common.utils.R;
    import com.sso.common.utils.ShiroUtils;
    import com.sso.system.shiro.UserToken;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.subject.Subject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import sun.misc.BASE64Encoder;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.Serializable;
    import java.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 登录
     */
    
    @Controller
    public class ChildLoginController extends BaseController {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
        @Autowired
        private UserOfficeService userOfficeService;
        @Autowired
        ChildMenuService menuService;
        @Autowired
        FileService fileService;
        @Autowired
        ChildUserService userService;
        @Autowired
        ChildDeptService deptService;
    
        @Log("请求访问主页")
        @GetMapping({ "/childIndex" })
        String childrenIndex(Model model) {
            List<Tree<ChildMenuDO>> menus = menuService.listMenuTree(getUserId());
            model.addAttribute("menus", menus);
            model.addAttribute("name", getUser().getName());
            model.addAttribute("username", getUser().getUsername());
            return "childIndex_v1";
        }
    
        @Log("请求访问渠道选择页")
        @GetMapping({ "/childIndex_choice" })
        String childrenIndex_choice(Model model) {
            Long userId = super.getUserId();
            //选出此用户下的所有的部门表
            List<ChildDeptDO> deptDOS = deptService.ListNameUrl(userId);
            List<ChildDeptVO> depts = new ArrayList<>();
            String username = super.getUsername();
            String name =super.getUser().getName();
            String uu = username + "," + userId;
            byte[] textByte = new byte[0];
            final BASE64Encoder encoder = new BASE64Encoder();
            try {
                textByte = uu.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    //编码
            final String encodedText = encoder.encode(textByte);
            //shiro的token
            Subject subject = SecurityUtils.getSubject();
            Serializable id = subject.getSession().getId();
            model.addAttribute("token",(String)id);
            if(null!=deptDOS && deptDOS.size()>0){
                for (int i = 0; i < deptDOS.size(); i++) {
                    ChildDeptDO childDept =  deptDOS.get(i);
                    List<OfficeDO> officeDO = userOfficeService.getOfficeByUserDept(
                            new HashMap(){{
                                put("deptId",childDept.getDeptId());
                                put("userId",userId);
                            }});
                    ChildDeptVO childDeptDO = new ChildDeptVO();
                    childDeptDO.setDeptId(childDept.getDeptId());
                    childDeptDO.setImgUrl(deptDOS.get(i).getImgUrl());
                    childDeptDO.setOfficeDOS(officeDO);
                    childDeptDO.setLoginUrl(deptDOS.get(i).getLoginUrl()+"?token="+(String)id+"&_cookie=true"+"&token_uu="+encodedText);
                    childDeptDO.setName(deptDOS.get(i).getName());
                    depts.add(childDeptDO);
                }
            }
            Gson gson = new Gson();
            List<ChildDeptVO> childDeptVOS = new ArrayList<>();
            List<ChildDeptVO> childJGDeptVOS = new ArrayList<>();
            for(int i = 0 ;i<depts.size();i++){
                ChildDeptVO childDeptVO = depts.get(i);
                if(childDeptVO.getOfficeDOS().size()>0){
                    String youJgDept = gson.toJson(childDeptVO);
                    ChildDeptVO childDeptvo =gson.fromJson(youJgDept,ChildDeptVO.class);
                    List<OfficeDO> offices = childDeptvo.getOfficeDOS();
                    OfficeToZtree officeToZtree = new OfficeToZtree(childDeptVO.getLoginUrl());
                    List<ZtreeVO> ztress = officeToZtree.change(offices);
                    childDeptvo.setZtreeVOS(ztress);
                    childJGDeptVOS.add(childDeptvo);
    
                }else{
                    String noJgDept = gson.toJson(childDeptVO);
                    childDeptVOS.add(gson.fromJson(noJgDept,ChildDeptVO.class));
                }
            }
            model.addAttribute("jGdepts",childJGDeptVOS);
            model.addAttribute("depts",childDeptVOS);
            model.addAttribute("name",name);
            return "childIndex_choice";
        }
    
        @GetMapping("/childLogout")
        String logout() {
            ShiroUtils.logout();
            return "redirect:/childrenLogin";
        }
    
        @GetMapping("/childMain")
        String childrenMain() {
            return "childMain";
        }
    
        @GetMapping("/childrenLogin")
        String childrenLogin() {
            return "childrenLogin";
        }
    
        @PostMapping("/childrenLogin")
        @ResponseBody
        public R childrenLogin(HttpServletRequest request){
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            password = MD5Utils.encrypt(username, password);
            UserToken token = new UserToken(username, password,"Children");
            Subject currentUser = SecurityUtils.getSubject();
            try {
                currentUser.login(token);
            } catch (UnknownAccountException e) {
                return R.error("账户不存在");
            }catch (IncorrectCredentialsException e) {
                return R.error("密码错误");
            }
            return R.childIndex("/mcpsso/childIndex_choice");
        }
    
    
    }
    View Code
     
  • 相关阅读:
    居中方法
    12个css实用技巧
    display元素来布局
    伪元素::before与:after
    弹性布局
    输入框下拉菜单
    HTMLinput日期输入类型
    模块XXXX可能与您正在运行的Windows版本不兼容。检查该模块是否与regsvr32.exe的x86(32位)x64(64位)版本兼容。
    Epoll为我们带来了什么
    C内存管理相关内容--取自高质量C++&C编程指南
  • 原文地址:https://www.cnblogs.com/TimeSay/p/12166983.html
Copyright © 2011-2022 走看看