Shiro session storage 和 session共享

Session Storage

为了方便应用程序能随时访问Session,Session在创建或更新之后,需要将其持久化。与持久化类似,当Session无效且使用时间较长时,需要删除Session,以防止Session的存储空间耗尽。

SessionDAO

Session的增、删、改、查等操作都由SessionManager的实现类委托给其内部组件SessionDAO完成。

当你使用的是native session时,session的默认存储在内存中。其实你还可以将Session存储在文件系统中、关系数据库或非关系型数据中等地方。

因为session的所有操作都是由SessionDAO完成的,所以,如果你想自定义session的存储位置,那么你需要编写SessionDAO的实现类。

其实,Shiro本身已经提供了SessionDAO的实现类,比如:AbstractSessionDAOCachingSessionDAOEnterpriseCacheSessionDAOMemorySessionDAO等,所以你只需要根据你的实际需要继承它们即可。

SessionDAO应用

自定义session的存储位置有什么用呢?其实,当你的应用程序部署多个节点,即使用了负载均衡,为了在多个节点之间共享session,你需要将session信息存储至缓存中。这时,你就需要自定义session的存储位置了。

下面显示了如何在多个节点之间共享session,示例代码中使用Redis作为session的存储媒介,示例代码如下。

java 代码

public class RedisSessionDAO extends AbstractSessionDAO {

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

    /**
     * The Redis key prefix for the sessions
     */
    private String keyPrefix = "shiro_session:";

    /**
     * shiro-redis的session对象前缀
     */
    private RedisManager redisManager;

    @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;
        }

        byte[] key = getByteKey(session.getId());
        byte[] value = SerializeUtils.serialize(session);
        session.setTimeout(redisManager.getExpire());
        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 getActiveSessions() {
        Set sessions = new HashSet();

        Set 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 sessionId
     */
    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;
        this.redisManager.init();
    }

    /**
     * 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;
    }
}

ini 配置代码

sessionDAO = com.xxx.xxx.RedisSessionDAO
securityManager.sessionManager.sessionDAO = $sessionDAO

你可能感兴趣的:(Shiro session storage 和 session共享)