Shiro 集成 Spring 之会话管理

栏目: Java · 发布时间: 5年前

内容简介:Shiro 提供了完整的会话管理功能,可以在不依赖底层容器,不仅可以在 WEB 环境下使用 Session,还可以在 JavaSE 环境下使用,且提供了会话管理,会话事件监听,会话持久化,过期支持。所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。获取 Session 方法:

Shiro 提供了完整的会话管理功能,可以在不依赖底层容器,不仅可以在 WEB 环境下使用 Session,还可以在 JavaSE 环境下使用,且提供了会话管理,会话事件监听,会话持久化,过期支持。

会话操作

所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。

获取 Session 方法:

Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();

Session 常用方法:

session.getId();					// 会话 ID, 唯一标识
session.getHost();  				// 获取当前 Subject 的主机地址

session.getTimeout();  				// 获取 Session 超时时间
session.setTimeout(long time);		// 设置 Session 超时时间

session.getStartTimestamp();		// 会话创建时间
session.getLastAccessTime();  		// 最后活跃时间

session.touch();					// 更新会话
session.stop(); 					// 销毁会话

// 当然也支持 getAttribute() 和 setAttribute() 方法

会话管理器

会话管理器管理应用中所有 Subject 的会话的创建、维护、删除、失效、验证等工作。

Shiro提供了三个默认实现:

DefaultSessionManager:DefaultSecurityManager 使用的默认实现,用于JavaSE环境;

ServletContainerSessionManager:DefaultWebSecurityManager使用的默认实现,用于Web环境,其直接使用Servlet容器的会话;

DefaultWebSessionManager:用于Web环境的实现,可以替代ServletContainerSessionManager,自己维护着会话,直接废弃了Servlet容器的会话管理。

会话监听器

会话监听器用于监听会话创建、过期及停止事件:

package im.zhaojun.session.listener;

import org.apache.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.springframework.stereotype.Component;

/**
 * Shiro 会话监听器
 */
@Component
public class MySessionListener implements SessionListener {
        
    private static final Logger logger = Logger.getLogger(MySessionListener.class);

    @Override
    public void onStart(Session session) {
        logger.info("create session : " + session.getId());
    }

    @Override
    public void onStop(Session session) {
        logger.info("session stop : " + session.getId());
    }

    @Override
    public void onExpiration(Session session) {
        logger.info("session expiration : " + session.getId());
    }
}

当然,如果你只想监听某个事件,可以继承自 SessionListenerAdapter

package im.zhaojun.session.listener;

import org.apache.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.SessionListenerAdapter;
import org.springframework.stereotype.Component;

/**
 * Shiro 会话监听器
 */
@Component
public class MySessionListener2 extends SessionListenerAdapter {
        
    private static final Logger logger = Logger.getLogger(MySessionListener2.class);

    @Override
    public void onStart(Session session) {
        logger.info("create session : " + session.getId());
    }
}

然后将会话监听器配置到 sessionManager 中,在将 sessionManager 配置到 securityManager

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm"/>
    <property name="cacheManager" ref="redisCacheManager"/>
    <property name="sessionManager" ref="sessionManager"/>
</bean>

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="sessionListeners" ref="mySessionListener"/>
</bean>

会话持久化/存储

Shiro 提供 SessionDAO 用于会话的 CRUD,我们可以用它来从 Redis 中增删改查 Session 信息,只需要继承自 SessionDAO

package im.zhaojun.session;

import im.zhaojun.util.JedisUtil;
import org.apache.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.stereotype.Component;
import org.springframework.util.SerializationUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;

@Component
public class RedisSessionDAO extends AbstractSessionDAO {
    private static final Logger logger = Logger.getLogger(RedisSessionDAO.class);

    @Resource
    private JedisUtil jedisUtil;

    private final String SHIRO_SESSION_PREFIX = "shiro-session:";

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        saveSession(session);
        logger.info("sessionDAO doCreate : " + session.getId());
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            return null;
        }
        byte[] key = getKeyBytes(sessionId.toString());
        byte[] value = jedisUtil.get(key);
        return (Session) SerializationUtils.deserialize(value);
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        saveSession(session);
    }

    @Override
    public void delete(Session session) {
        logger.info("session delete : " + session.getId());
        if (session != null && session.getId() != null) {
            byte[] key = getKeyBytes(session.getId().toString());
            jedisUtil.del(key);
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Collection<byte[]> keys = jedisUtil.getKeysByPrefix(SHIRO_SESSION_PREFIX);
        Collection<Session> sessions = new HashSet<>();
        if (sessions.isEmpty()) {
            return sessions;
        }
        for (byte[] key : keys) {
            Session session = (Session) SerializationUtils.deserialize(jedisUtil.get(key));
            sessions.add(session);
        }
        return sessions;
    }

    private byte[] getKeyBytes(String key) {
        return (SHIRO_SESSION_PREFIX + key).getBytes();
    }

    private void saveSession(Session session) {
        if (session != null && session.getId() != null) {
            byte[] key = getKeyBytes(session.getId().toString());
            byte[] value = SerializationUtils.serialize(session);
            jedisUtil.set(key, value);
            jedisUtil.expire(key, 600);
        }
    }
}

这里和上一章,授权数据的缓存很相像,那里是对授权数据的增删改查,这里是对 Session 数据的增删改查。

然后将其配置到 sessionManager 中:

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="sessionListeners" ref="mySessionListener"/>
    <property name="sessionDAO" ref="redisSessionDAO"/>
</bean>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

剑指Offer:名企面试官精讲典型编程题(第2版)

剑指Offer:名企面试官精讲典型编程题(第2版)

何海涛 / 电子工业出版社 / 2017-5 / 65.00

《剑指Offer:名企面试官精讲典型编程题(第2版)》剖析了80个典型的编程面试题,系统整理基础知识、代码质量、解题思路、优化效率和综合能力这5个面试要点。《剑指Offer:名企面试官精讲典型编程题(第2版)》共分7章,主要包括面试的流程,讨论面试每一环节需要注意的问题;面试需要的基础知识,从编程语言、数据结构及算法三方面总结程序员面试知识点;高质量的代码,讨论影响代码质量的3个要素(规范性、完整......一起来看看 《剑指Offer:名企面试官精讲典型编程题(第2版)》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具