博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java使用reids,以及redis与shiro集成
阅读量:7050 次
发布时间:2019-06-28

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

什么是redis:redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。(我也是百度的,个人理解reids就是个比较轻量级的key——value模式的数据库,这个数据库的存储性能很好,可以用来代替缓存实现的很多功能。而且这个redis数据库是第三方独立的服务,可以用在负载均衡情况下多个服务器,多个web容器之间公用数据的缓存。)
要使用reids,首先可以到官网reids的jar包和redis。
然后把redis的jar包导入到项目中。
我用的版本是2.1.0. 系统是32位的,所以我解压了32位的redis服务。
打开以后使用里面的redis-servier。exe来启动redis服务。启动后的结果如下图所示
 
package org.calonlan.security.component;import java.util.Iterator;import java.util.Set;import org.springframework.beans.factory.annotation.Value;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * @author Administrator *         redismanager主要用来给用户提供一个设计完备的,通过jedis的jar包来管理redis内存数据库的各种方法 */public class RedisManager {    // ip和port属性都定义在了properties文件中,这里通过spring的注解方式来直接使用    @Value("${redis.ip}")    private String host;    @Value("${redis.port}")    private int port;    // 设置为0的话就是永远都不会过期    private int expire = 0;    // 定义一个管理池,所有的redisManager共同使用。    private static JedisPool jedisPool = null;    public RedisManager() {    }    /**     *      * 初始化方法,在这个方法中通过host和port来初始化jedispool。     *      * */    public void init() {        if (null == host || 0 == port) {            System.out.println("请初始化redis配置文件");            throw new NullPointerException("找不到redis配置");        }        if (jedisPool == null) {            jedisPool = new JedisPool(new JedisPoolConfig(), host, port);        }    }    /**     * get value from redis     *      * @param key     * @return     */    public byte[] get(byte[] key) {        byte[] value = null;        Jedis jedis = jedisPool.getResource();        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * get value from redis     *      * @param key     * @return     */    public String get(String key) {        String value = null;        Jedis jedis = jedisPool.getResource();        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public byte[] set(byte[] key, byte[] value) {        Jedis jedis = jedisPool.getResource();        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public String set(String key, String value) {        Jedis jedis = jedisPool.getResource();        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public byte[] set(byte[] key, byte[] value, int expire) {        Jedis jedis = jedisPool.getResource();        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public String set(String key, String value, int expire) {        Jedis jedis = jedisPool.getResource();        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * del     *      * @param key     */    public void del(byte[] key) {        Jedis jedis = jedisPool.getResource();        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * del     *      * @param key     */    public void del(String key) {        Jedis jedis = jedisPool.getResource();        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * flush     */    public void flushDB() {        Jedis jedis = jedisPool.getResource();        try {            jedis.flushDB();        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * size     */    public Long dbSize() {        Long dbSize = 0L;        Jedis jedis = jedisPool.getResource();        try {            dbSize = jedis.dbSize();        } finally {            jedisPool.returnResource(jedis);        }        return dbSize;    }    /**     * keys     *      * @param regex     * @return     */    public Set
keys(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); try { keys = jedis.keys(pattern.getBytes()); } finally { jedisPool.returnResource(jedis); } return keys; } public void dels(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); try { keys = jedis.keys(pattern.getBytes()); Iterator
ito = keys.iterator(); while (ito.hasNext()) { jedis.del(ito.next()); } } finally { jedisPool.returnResource(jedis); } } 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; }}

这里的redisManager是通过spring来进行管理的,所以直接使用了@value来读取properties文件中的属性。properties文件的内容如下:

    redis.ip=127.0.0.1         redis.port=6379

ip定义为本机的ip,端口是redis默认的6379端口。

classpath:/config/jdbc.properties
classpath:/config/redis.properties
在spring中就是在这个地方把reids服务的配置文件redis.properties文件加载到spring中管理的。
 
 
这样redis服务就集成到了项目中,具体的使用,通过对shiro默认缓存和session数据的缓存的保存过程来展示。
 
项目中遇到的问题是这样的,在同时使用一个机器使用多个web容器或者多个机器同时来为一个项目进行负载均衡时,shiro的默认缓存和session数据无法在多个web容器或者多个机器之间进行同步。为了达到多web容器或多机器负载均衡的目的,我们修改了shiro的默认session管理器和缓存管理器来使shiro通过redis来管理session和缓存。这样多个web容器或机器之间的数据就可以互通共用了。
首先是shiro的配置文件,我用的是spring集成的方式。
 
customShiroSessionDAO" /> //这里指定shiro的sessionManager使用我们指定的存储方式来存放session信息
//自己定义的sessiondao
//注册上面实现的redisManager到spring中
customShiroCacheManager" />
/img/** =anon /ueditor/jsp/upload/** =anon /login = authc /authenticated = authc /css/** = anon /common/** = anon /js/** = anon /admin/** = user,sysUser //*=anon
主要看上图的红色部分:其中customShiroSessionDAO、jedisShiroSessionRepository用来处理session;customShiroCacheManager、jedisShiroCacheManager用来处理缓存。
 
他们的源代码如下:
 
package org.calonlan.security.component;import java.io.Serializable;import java.util.Collection;import org.apache.shiro.session.Session;import org.apache.shiro.session.UnknownSessionException;import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;public class CustomShiroSessionDao extends AbstractSessionDAO {    private ShiroSessionRepository shiroSessionRepository;    public ShiroSessionRepository getShiroSessionRepository() {        return shiroSessionRepository;    }    public void setShiroSessionRepository(            ShiroSessionRepository shiroSessionRepository) {        this.shiroSessionRepository = shiroSessionRepository;    }    @Override    public void delete(Session session) {        if (session == null) {            System.out.println("错误");            return;        }        Serializable id = session.getId();        if (id != null)            getShiroSessionRepository().deleteSession(id);    }    @Override    public Collection
getActiveSessions() { return getShiroSessionRepository().getAllSessions(); } @Override public void update(Session session) throws UnknownSessionException { getShiroSessionRepository().saveSession(session); } @Override protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); getShiroSessionRepository().saveSession(session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { return getShiroSessionRepository().getSession(sessionId); }}

 

这里我们是继承了shiro的AbstractSessionDAO,然后仿照shiro的模式,给他一个shiroSessionRepository,来进行详细的session存储操作。

 

package org.calonlan.security.component;import java.io.Serializable;import java.util.Collection;import org.apache.shiro.session.Session;public interface ShiroSessionRepository {    void saveSession(Session session);    void deleteSession(Serializable sessionId);    Session getSession(Serializable sessionId);    Collection
getAllSessions();}
package org.calonlan.security.component;import java.io.Serializable;import java.util.Collection;import java.util.HashSet;import java.util.Set;import org.apache.shiro.session.Session;public class JedisShiroSessionRepository implements ShiroSessionRepository {    /**     *      * redis session key 前缀     *      * */    private final String REDIS_SHIRO_SESSION = "shiro-session";    private RedisManager redisManager;    @Override    public void saveSession(Session session) {        redisManager.init();        if (session == null || session.getId() == null) {            System.out.println("session 或者 session ID 为空");        }        byte[] key = SerializeUtils.serialize(getRedisSessionKey(session                .getId()));        byte[] value = SerializeUtils.serialize(session);        Long timeOut = session.getTimeout() / 1000;        redisManager.set(key, value, Integer.parseInt(timeOut.toString()));    }    @Override    public void deleteSession(Serializable sessionId) {        redisManager.init();        if (sessionId == null) {            System.out.println("id为空");        }        redisManager.del(SerializeUtils                .serialize(getRedisSessionKey(sessionId)));    }    @Override    public Session getSession(Serializable sessionId) {        redisManager.init();        if (null == sessionId) {            System.out.println("id为空");            return null;        }        Session session = null;        byte[] value = redisManager.get(SerializeUtils                .serialize(getRedisSessionKey(sessionId)));        if (null == value)            return null;        session = (Session) SerializeUtils.deserialize(value);        return session;    }    @Override    public Collection
getAllSessions() { redisManager.init(); Set
sessions = new HashSet
(); Set
byteKeys = redisManager .keys(this.REDIS_SHIRO_SESSION + "*"); if (byteKeys != null && byteKeys.size() > 0) { for (byte[] bs : byteKeys) { Session s = (Session) SerializeUtils.deserialize(redisManager .get(bs)); sessions.add(s); } } return sessions; } /** * 获取redis中的session key * * @param sessionId * @return */ private String getRedisSessionKey(Serializable sessionId) { return this.REDIS_SHIRO_SESSION + sessionId; } public RedisManager getRedisManager() { return redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; } public JedisShiroSessionRepository() { } // public static void main(String[] args) { // Jedis jj = new Jedis("localhost"); // //jj.set("key2", "232323231========="); // String ss = jj.get("key1"); // System.out.println(jj.get("key2")); // System.out.println(ss); // }}
package org.calonlan.security.component;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.util.Destroyable;public class CustomShiroCacheManager implements CacheManager, Destroyable {    private ShiroCacheManager shrioCacheManager;    public ShiroCacheManager getShrioCacheManager() {        return shrioCacheManager;    }    public void setShrioCacheManager(ShiroCacheManager shrioCacheManager) {        this.shrioCacheManager = shrioCacheManager;    }    @Override    public void destroy() throws Exception {        getShrioCacheManager().destroy();    }    @Override    public 
Cache
getCache(String name) throws CacheException { return getShrioCacheManager().getCache(name); }}
package org.calonlan.security.component;import org.apache.shiro.cache.Cache;public interface ShiroCacheManager {    
Cache
getCache(String name); void destroy(); }
package org.calonlan.security.component;import org.apache.shiro.cache.Cache;public class JedisShiroCacheManager implements ShiroCacheManager {    private RedisManager redisManager;    public RedisManager getRedisManager() {        return redisManager;    }    public void setRedisManager(RedisManager redisManager) {        this.redisManager = redisManager;    }    @Override    public 
Cache
getCache(String name) { return new JedisShiroCache
(redisManager, name); } @Override public void destroy() { redisManager.init(); redisManager.flushDB(); }}
具体的使用就如如上代码所示,为什么要弄一个什么ShiroCacheManager和ShiroSessionRepository接口呢,我想各位大侠也能知道的。有了这个两个接口,我们就可以通过这个两个接口来实现更多形式的shiro的session和缓存的管理了。
 
 
在很多地方使用到了SerializeUtils,它的作用就是把对象转化为byte数组,或把byte数组转化为对象。源代码如下:
 
package org.calonlan.security.component;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class SerializeUtils {    public static byte[] serialize(Object o) {        ByteArrayOutputStream out = new ByteArrayOutputStream();        try {            ObjectOutputStream outo = new ObjectOutputStream(out);            outo.writeObject(o);        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return out.toByteArray();    }    public static Object deserialize(byte[] b) {        ObjectInputStream oin;        try {            oin = new ObjectInputStream(new ByteArrayInputStream(b));            try {                return oin.readObject();            } catch (ClassNotFoundException e) {                // TODO Auto-generated catch block                e.printStackTrace();                return null;            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();            return null;        }    }}
然后项目的运行结果如下:
 
从图中可以看到,我登录后,session信息已经保存到了redis数据库中。多个tomcat做负载均衡的测试结果也很良好,但是我这个笔记本没有安装那种环境,所以无法测试。这都是个人一点小东西,各位大神勿喷。
 
 
12.10日补充更新,为了让redis数据库能安全的使用,(在实际生产环境中我们也是这样要求的)我们需要给redis数据库设置密码;在windows环境下是这样的。
 
首先进入32bit目录中,找到redis.conf文件,在文件中做如下修改:
找到# requirepass foobared
修改为 requirepass 你的密码。
 
然后在DOS环境下进入你的redis-server.exe所在的目录
执行如下命令:redis-server.exe reids.conf 从dos中来启动redis服务,这样你的conf中配置才会生效。
对应的我修改了redisManager的代码。
 
package org.calonlan.security.component;import java.util.Iterator;import java.util.Set;import org.springframework.beans.factory.annotation.Value;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * @author Administrator *         redismanager主要用来给用户提供一个设计完备的,通过jedis的jar包来管理redis内存数据库的各种方法 */public class RedisManager {    // ip和port属性都定义在了properties文件中,这里通过spring的注解方式来直接使用    @Value("${redis.ip}")    private String host;    @Value("${redis.port}")    private int port;    // 设置为0的话就是永远都不会过期    private int expire = 0;    // 定义一个管理池,所有的redisManager共同使用。    private static JedisPool jedisPool = null;    public RedisManager() {    }    /**     *      * 初始化方法,在这个方法中通过host和port来初始化jedispool。     *      * */    public void init() {        if (null == host || 0 == port) {            System.out.println("请初始化redis配置文件");            throw new NullPointerException("找不到redis配置");        }        if (jedisPool == null) {            jedisPool = new JedisPool(new JedisPoolConfig(), host, port);        }    }    /**     * get value from redis     *      * @param key     * @return     */    public byte[] get(byte[] key) {        byte[] value = null;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * get value from redis     *      * @param key     * @return     */    public String get(String key) {        String value = null;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public byte[] set(byte[] key, byte[] value) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public String set(String key, String value) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public byte[] set(byte[] key, byte[] value, int expire) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public String set(String key, String value, int expire) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * del     *      * @param key     */    public void del(byte[] key) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * del     *      * @param key     */    public void del(String key) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * flush     */    public void flushDB() {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.flushDB();        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * size     */    public Long dbSize() {        Long dbSize = 0L;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            dbSize = jedis.dbSize();        } finally {            jedisPool.returnResource(jedis);        }        return dbSize;    }    /**     * keys     *      * @param regex     * @return     */    public Set
keys(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); jedis.auth("你的密码"); try { System.out.println("我调用了keys方法=---shiro"); keys = jedis.keys(("*" + pattern).getBytes()); if (null != keys) System.out.println(keys.size()); } finally { jedisPool.returnResource(jedis); } return keys; } public void dels(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); jedis.auth("你的密码"); try { System.out.println("我调用了dels方法=---shiro"); keys = jedis.keys(("*" + pattern).getBytes());//这里我做了修改,在redis数据库中我们的id前面还加了一堆东西,这样修改后就可以全部查看到了 Iterator
ito = keys.iterator(); while (ito.hasNext()) { jedis.del(ito.next()); } } finally { jedisPool.returnResource(jedis); } } 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; }}
我在代码中还做了一下修改,代码中也做了注释。修改的地方是keys = jedis.keys(("*" + pattern).getBytes()); 在所有的pattern前面都加上*号了,因为我看到在redis实际使用的时候不加*号是查询不到结果的。因为redis在我们的id前面加了一堆东西;但是在使用get的时候却是没问题的,直接通过id就能取到值··这个我还没弄懂· ··希望有高手看到以后能指点一下;我也会继续研究。
 
12.10下午6点··今天休息··多想想了··问题解决了。更新的代码主要包括一下内容:
 
package org.calonlan.security.component;import java.io.Serializable;import java.util.Collection;import java.util.HashSet;import java.util.Set;import org.apache.shiro.session.Session;public class JedisShiroSessionRepository implements ShiroSessionRepository {    /**     *      * redis session key 前缀     *      * */    private final String REDIS_SHIRO_SESSION = "shiro-session";    private RedisManager redisManager;    @Override    public void saveSession(Session session) {        redisManager.init();        if (session == null || session.getId() == null) {            System.out.println("session 或者 session ID 为空");        }        byte[] key = getRedisSessionKey(session.getId()).getBytes();        byte[] value = SerializeUtils.serialize(session);        Long timeOut = session.getTimeout() / 1000;        redisManager.set(key, value, Integer.parseInt(timeOut.toString()));    }    @Override    public void deleteSession(Serializable sessionId) {        redisManager.init();        if (sessionId == null) {            System.out.println("id为空");        }        redisManager.del(getRedisSessionKey(sessionId).getBytes());    }    @Override    public Session getSession(Serializable sessionId) {        redisManager.init();        if (null == sessionId) {            System.out.println("id为空");            return null;        }        Session session = null;        byte[] value = redisManager.get(getRedisSessionKey(sessionId)                .getBytes());        if (null == value)            return null;        session = (Session) SerializeUtils.deserialize(value);        return session;    }    @Override    public Collection
getAllSessions() { redisManager.init(); Set
sessions = new HashSet
(); Set
byteKeys = redisManager .keys(this.REDIS_SHIRO_SESSION + "*"); if (byteKeys != null && byteKeys.size() > 0) { for (byte[] bs : byteKeys) { Session s = (Session) SerializeUtils.deserialize(redisManager .get(bs)); sessions.add(s); } } return sessions; } /** * 获取redis中的session key * * @param sessionId * @return */ private String getRedisSessionKey(Serializable sessionId) { return this.REDIS_SHIRO_SESSION + sessionId; } public RedisManager getRedisManager() { return redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; } public JedisShiroSessionRepository() { } // public static void main(String[] args) { // Jedis jj = new Jedis("localhost"); // //jj.set("key2", "232323231========="); // String ss = jj.get("key1"); // System.out.println(jj.get("key2")); // System.out.println(ss); // }}
package org.calonlan.security.component;import java.util.Collection;import java.util.HashSet;import java.util.LinkedList;import java.util.List;import java.util.Set;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;public class JedisShiroCache
implements Cache
{ private final String REDIS_SHIRO_CACHE = "shiro-cache"; private RedisManager redisManager; private String name; public JedisShiroCache(RedisManager redisManager, String name) { this.redisManager = redisManager; this.name = name; } public String getName() { if (null == null) { return ""; } return name; } public void setName(String name) { this.name = name; } @Override public void clear() throws CacheException { redisManager.init(); String keysPattern = this.REDIS_SHIRO_CACHE + "*"; redisManager.flushDB(); } @Override public V get(K key) throws CacheException { redisManager.init(); byte[] byteKey = getCacheKey(key).getBytes(); byte[] byteValue = redisManager.get(byteKey); if (null == byteValue) return null; return (V) SerializeUtils.deserialize(byteValue); } @Override public Set
keys() { redisManager.init(); Set
byteSet = redisManager.keys(this.REDIS_SHIRO_CACHE + "*"); Set
keys = new HashSet
(); for (byte[] bs : byteSet) { keys.add((K) SerializeUtils.deserialize(bs)); } return keys; } @Override public V put(K key, V value) throws CacheException { redisManager.init(); V previos = get(key); redisManager.set(getCacheKey(key).getBytes(), SerializeUtils.serialize(value)); return previos; } @Override public V remove(K key) throws CacheException { redisManager.init(); V previos = get(key); redisManager.del(getCacheKey(key).getBytes()); return previos; } @Override public int size() { redisManager.init(); if (keys() == null) return 0; return keys().size(); } @Override public Collection
values() { Set
byteSet = redisManager.keys(this.REDIS_SHIRO_CACHE + "*"); List
result = new LinkedList
(); for (byte[] bs : byteSet) { result.add((V) SerializeUtils.deserialize(redisManager.get(bs))); } return result; } private String getCacheKey(Object key) { return this.REDIS_SHIRO_CACHE + getName() + ":" + key; }}
package org.calonlan.security.component;import java.util.Iterator;import java.util.Set;import org.springframework.beans.factory.annotation.Value;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * @author Administrator *         redismanager主要用来给用户提供一个设计完备的,通过jedis的jar包来管理redis内存数据库的各种方法 */public class RedisManager {    // ip和port属性都定义在了properties文件中,这里通过spring的注解方式来直接使用    @Value("${redis.ip}")    private String host;    @Value("${redis.port}")    private int port;    // 设置为0的话就是永远都不会过期    private int expire = 0;    // 定义一个管理池,所有的redisManager共同使用。    private static JedisPool jedisPool = null;    public RedisManager() {    }    /**     *      * 初始化方法,在这个方法中通过host和port来初始化jedispool。     *      * */    public void init() {        if (null == host || 0 == port) {            System.out.println("请初始化redis配置文件");            throw new NullPointerException("找不到redis配置");        }        if (jedisPool == null) {            jedisPool = new JedisPool(new JedisPoolConfig(), host, port);        }    }    /**     * get value from redis     *      * @param key     * @return     */    public byte[] get(byte[] key) {        byte[] value = null;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * get value from redis     *      * @param key     * @return     */    public String get(String key) {        String value = null;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            value = jedis.get(key);        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public byte[] set(byte[] key, byte[] value) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @return     */    public String set(String key, String value) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (this.expire != 0) {                jedis.expire(key, this.expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public byte[] set(byte[] key, byte[] value, int expire) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * set     *      * @param key     * @param value     * @param expire     * @return     */    public String set(String key, String value, int expire) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.set(key, value);            if (expire != 0) {                jedis.expire(key, expire);            }        } finally {            jedisPool.returnResource(jedis);        }        return value;    }    /**     * del     *      * @param key     */    public void del(byte[] key) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * del     *      * @param key     */    public void del(String key) {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.del(key);        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * flush     */    public void flushDB() {        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            jedis.flushDB();        } finally {            jedisPool.returnResource(jedis);        }    }    /**     * size     */    public Long dbSize() {        Long dbSize = 0L;        Jedis jedis = jedisPool.getResource();        jedis.auth("你的密码");        try {            dbSize = jedis.dbSize();        } finally {            jedisPool.returnResource(jedis);        }        return dbSize;    }    /**     * keys     *      * @param regex     * @return     */    public Set
keys(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); jedis.auth("你的密码"); try { System.out.println("我调用了keys方法=---shiro"); keys = jedis.keys(pattern.getBytes()); if (null != keys) System.out.println(keys.size()); } finally { jedisPool.returnResource(jedis); } return keys; } public void dels(String pattern) { Set
keys = null; Jedis jedis = jedisPool.getResource(); jedis.auth("你的密码"); try { System.out.println("我调用了dels方法=---shiro"); keys = jedis.keys(pattern.getBytes()); Iterator
ito = keys.iterator(); while (ito.hasNext()) { jedis.del(ito.next()); } } finally { jedisPool.returnResource(jedis); } } 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; }}
主要更改了这三个类,做的主要修改就是这句,byte[] key = getRedisSessionKey(session.getId()).getBytes();这句很重要,以前我们的key和value一样是用serilizableUtil在转换为byte数组的。但是我们这样转换会有一个问题。就是会有OBJECT标识,因为我们使用了对象流··。大家可以看serilizableutil的代码。然后我给大家看看修改前和修改后在数据库中看到的不同景象;
修改前:
可以看到我们定义的key前面多了一堆/xac/xed#$^%^$%^$%^$这样的东西,个人理解这就是类标识吧···
修改后:
可以看到我们的id就是按我们定义的样子在显示着··虽然是用byte数组传递过去的··
 
然后的redismanager中,我们使用keys(“shiro-session*”)也可以列出需要的所有的key了···
 
就这样··也许还会有问题····也希望高手能给批评意见。
 
有人反应我出现在配置文件中的类有几个没有贴出来,首先很感谢您的指正;在这里我主要说shiro和redis的结合。至于shiro的配置使用不在这篇博文中讨论。但是鉴于有人要看我就贴出来。
 
SpringCacheManagerWrapper
 
/** * Copyright (c) 2005-2012 https://github.com/zhangkaitao * * Licensed under the Apache License, Version 2.0 (the "License"); */package org.calonlan.security.spring;import net.sf.ehcache.Ehcache;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.util.CollectionUtils;import org.springframework.cache.support.SimpleValueWrapper;import java.util.*;/** * 包装Spring cache抽象 * 

User: Zhang Kaitao *

Date: 13-3-23 上午8:26 *

Version: 1.0 */public class SpringCacheManagerWrapper implements CacheManager { private org.springframework.cache.CacheManager cacheManager; /** * 设置spring cache manager * * @param cacheManager */ public void setCacheManager(org.springframework.cache.CacheManager cacheManager) { this.cacheManager = cacheManager; } @Override public

Cache
getCache(String name) throws CacheException { org.springframework.cache.Cache springCache = cacheManager.getCache(name); return new SpringCacheWrapper(springCache); } static class SpringCacheWrapper implements Cache { private org.springframework.cache.Cache springCache; SpringCacheWrapper(org.springframework.cache.Cache springCache) { this.springCache = springCache; } @Override public Object get(Object key) throws CacheException { Object value = springCache.get(key); if (value instanceof SimpleValueWrapper) { return ((SimpleValueWrapper) value).get(); } return value; } @Override public Object put(Object key, Object value) throws CacheException { springCache.put(key, value); return value; } @Override public Object remove(Object key) throws CacheException { springCache.evict(key); return null; } @Override public void clear() throws CacheException { springCache.clear(); } @Override public int size() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); return ehcache.getSize(); } throw new UnsupportedOperationException("invoke spring cache abstract size method not supported"); } @Override public Set keys() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); return new HashSet(ehcache.getKeys()); } throw new UnsupportedOperationException("invoke spring cache abstract keys method not supported"); } @Override public Collection values() { if(springCache.getNativeCache() instanceof Ehcache) { Ehcache ehcache = (Ehcache) springCache.getNativeCache(); List keys = ehcache.getKeys(); if (!CollectionUtils.isEmpty(keys)) { List values = new ArrayList(keys.size()); for (Object key : keys) { Object value = get(key); if (value != null) { values.add(value); } } return Collections.unmodifiableList(values); } else { return Collections.emptyList(); } } throw new UnsupportedOperationException("invoke spring cache abstract values method not supported"); } }}

 

RetryLimitHashedCredentialsMatcher:

 

package org.calonlan.security.credentials;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.ExcessiveAttemptsException;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheManager;import java.util.concurrent.atomic.AtomicInteger;/** * 

User: Zhang Kaitao *

Date: 14-1-28 *

Version: 1.0 */public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher { private Cache

passwordRetryCache; public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) { passwordRetryCache = cacheManager.getCache("passwordRetryCache"); } @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { String username = (String)token.getPrincipal(); //retry count + 1 AtomicInteger retryCount = passwordRetryCache.get(username); if(retryCount == null) { retryCount = new AtomicInteger(0); passwordRetryCache.put(username, retryCount); } if(retryCount.incrementAndGet() > 5) { //if retry count > 5 throw throw new ExcessiveAttemptsException(); } boolean matches = super.doCredentialsMatch(token, info); if(matches) { //clear retry count passwordRetryCache.remove(username); } return matches; }}

 UserRealm:

package org.calonlan.security.realm;import org.apache.log4j.Logger;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.cache.Cache;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.calonlan.security.entity.User;import org.calonlan.security.service.ResourceService;import org.calonlan.security.service.UserRoleService;import org.calonlan.security.service.UserService;/** * @ClassName: UserRealm * @Description: TODO(这里用一句话描述这个类的作用) * @author mbc * @date 2014-6-7 上午11:49:06 *  */public class UserRealm extends AuthorizingRealm {    private static final Logger logger = Logger.getLogger(UserRealm.class);    @javax.annotation.Resource    private UserRoleService userRoleService;    @javax.annotation.Resource    private ResourceService resourceService;    @javax.annotation.Resource    private UserService userService;    /*     * (非 Javadoc) 

Title: doGetAuthorizationInfo

Description:权限授权

* * @param principals * * @return * * @see * org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache * .shiro.subject.PrincipalCollection) */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // 为空的情况直接返回null if (null == principals) { return null; } SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); String username = (String) principals.getPrimaryPrincipal(); Cache
cache = getAuthenticationCache(); System.out.println(cache == null); logger.info("[用户:" + username + "|权限授权]"); authorizationInfo.setRoles(userRoleService .loadRoleIdsByUsername(username)); authorizationInfo.setStringPermissions(resourceService .loadPermissionsByUsername(username)); logger.info("[用户:" + username + "|权限授权完成]"); return authorizationInfo; } /* * (非 Javadoc)

Title: doGetAuthenticationInfo

Description:权限认证 *

* * @param token * * @return * * @throws AuthenticationException * * @see * org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org * .apache.shiro.authc.AuthenticationToken) */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { SimpleAuthenticationInfo authenticationInfo; String username = (String) token.getPrincipal(); logger.info("[用户:" + username + "|系统权限认证]"); User user = userService.loadByUsername(username); if (user != null) { if ("帐号锁定".equals(user.getState())) { throw new LockedAccountException();// 帐号锁定 } // 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现 authenticationInfo = new SimpleAuthenticationInfo( user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()), getName());// realm logger.info("[用户:" + username + "|系统权限认证完成]"); return authenticationInfo; // name } else return null; }}

 

你可能感兴趣的文章
Android开发和调试必备工具-SDK Tools
查看>>
【LeetCode】107. Binary Tree Level Order Traversal II (2 solutions)
查看>>
《微软的软件测试之道》读书笔记 之 结构测试技术
查看>>
ASP.NET中Session的个人浅谈
查看>>
数学图形之Kuen Surface
查看>>
统计图表类型选择应用总结&表数据挖掘方法及应用
查看>>
【故障处理】CRS-1153错误处理
查看>>
快来熟练使用 Mac 编程
查看>>
ASP.NET MVC 3 网站优化总结(三)Specify Vary: Accept-Encoding header
查看>>
MVC5 + EF6 简单示例
查看>>
Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****
查看>>
ORACLE里锁有以下几种模式,v$locked_object,locked_mode
查看>>
【树莓派】Linux 测网速及树莓派源
查看>>
Java用户线程和守护线程
查看>>
[TypeScript] Use the never type to avoid code with dead ends using TypeScript
查看>>
Javascript 与 SPA单页Web富应用
查看>>
SpringMVC之访问静态文件
查看>>
【java设计模式】之 模板方法(Template Method)模式
查看>>
【踩坑速记】MIUI系统BUG,调用系统相机拍照可能会带给你的一系列坑,将拍照适配方案进行到底!...
查看>>
小米手机会不会更好
查看>>