7.shiro的会话管理

shiro的会话管理

1.三个会话管理器(SessionManager)实现

1.1DefaultSessionManager

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

1.2ServletContainerSessionManager

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

1.3DefaultWebSessionManager

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

se环境下的 ini 配置 (shiro.ini):
[main]
sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager
securityManager.sessionManager=$sessionManager;

Web 环境下的 ini 配置 (shiro-web.ini):
[main]
sessionManager=org.apache.shiro.web.session.mgt.ServletContainerSessionManager  #DefaultWebSessionManager
securityManager.sessionManager=$sessionManager

2.会话监听器

2.1SessionListener 和 SessionListenerAdapter

1.SessionListener实现方法并重写三个接口

public class MySessionListener1 implements SessionListener {
    @Override
    public void onStart(Session session) {//会话创建时触发
        System.out.println("会话创建:" + session.getId());
    }
    @Override
    public void onExpiration(Session session) {//会话过期时触发
        System.out.println("会话过期:" + session.getId());
    }
    @Override
    public void onStop(Session session) {//退出/会话过期时触发
        System.out.println("会话停止:" + session.getId());
    }  
}

2.SessionListenerAdapter (区别于SessionListen :可以只使用其中的一个方法)

public class MySessionListener2 extends SessionListenerAdapter {
    @Override
    public void onStart(Session session) {
        System.out.println("会话创建:" + session.getId());
    }
}

shiro.ini文件配置

[main]
sessionListener1=com.github.shiro.web.listener.MySessionListener1
sessionListener2=com.github.shiro.web.listener.MySessionListener2
sessionManager.sessionListeners=$sessionListener1,$sessionListener2

3.会话存储

3.1SessionDao常用实现类

AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话 ID 等;
CachingSessionDAO 提供了对开发者透明的会话缓存的功能,只需要设置相应的 CacheManager 即可;
MemorySessionDAO 直接在内存中进行会话维护;EnterpriseCacheSessionDAO 提供了缓存功能的会话维护,默认情况下使用 MapCache 实现,内部使用 ConcurrentHashMap 保存缓存的会话。

3.2SessionDao的配置

Shiro 提供了使用 Ehcache 进行会话存储,Ehcache 可以配合 TerraCotta 实现容器无关的分布式集群。

org.apache.shiro
shiro-ehcache
1.2.2
 
配置 shiro-web.ini 文件

sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO. activeSessionsCacheName=shiro-activeSessionCache
sessionManager.sessionDAO=$sessionDAO
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile=classpath:ehcache.xml
securityManager.cacheManager = $cacheManager;

sessionDAO. activeSessionsCacheName:设置 Session 缓存名字,默认就是 shiro-activeSessionCache;
cacheManager:缓存管理器,用于管理缓存的,此处使用 Ehcache 实现;
cacheManager.cacheManagerConfigFile:设置 ehcache 缓存的配置文件;
securityManager.cacheManager:设置 SecurityManager 的 cacheManager,会自动设置实现了 CacheManagerAware 接口的相应对象,如 SessionDAO 的 cacheManager;
配置 ehcache.xml:

<cache name="shiro-activeSessionCache"
       maxEntriesLocalHeap="10000"
       overflowToDisk="false"
       eternal="false"
       diskPersistent="false"
       timeToLiveSeconds="0"
       timeToIdleSeconds="0"
       statistics="true"/>

Cache 的名字为 shiro-activeSessionCache,即设置的 sessionDAO 的 activeSessionsCacheName 属性值。
另外可以通过如下 ini 配置设置会话 ID 生成器:

sessionIdGenerator=org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator
sessionDAO.sessionIdGenerator=$sessionIdGenerator;

3.3自定义实现

自定义实现 SessionDAO,继承 CachingSessionDAO 即可:

public class MySessionDAO extends CachingSessionDAO {
    private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
     protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        String sql = "insert into sessions(id, session) values(?,?)";
        jdbcTemplate.update(sql, sessionId, SerializableUtils.serialize(session));
        return session.getId();
    }
protected void doUpdate(Session session) {
    if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid()) {
        return; //如果会话过期/停止 没必要再更新了
    }
        String sql = "update sessions set session=? where id=?";
        jdbcTemplate.update(sql, SerializableUtils.serialize(session), session.getId());
    }
    protected void doDelete(Session session) {
        String sql = "delete from sessions where id=?";
        jdbcTemplate.update(sql, session.getId());
    }
    protected Session doReadSession(Serializable sessionId) {
        String sql = "select session from sessions where id=?";
        List<String> sessionStrList = jdbcTemplate.queryForList(sql, String.class, sessionId);
        if(sessionStrList.size() == 0) return null;
        return SerializableUtils.deserialize(sessionStrList.get(0));
    }
};

doCreate/doUpdate/doDelete/doReadSession 分别代表创建 / 修改 / 删除 / 读取会话;此处通过把会话序列化后存储到数据库实现;接着在 shiro-web.ini 中配置:

sessionDAO=com.github.shiro.session.dao.MySessionDAO

其他设置和之前一样,因为继承了 CachingSessionDAO;所有在读取时会先查缓存中是否存在,如果找不到才到数据库中查找。

4.验证会话是否过期

Shiro 提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话;出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的;
但是如在 web 环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro 提供了会话验证调度器

4.1SessionValidationScheduler 会话验证调度器

sessionValidationScheduler=org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 3600000
sessionValidationScheduler.sessionManager=$sessionManager
sessionManager.globalSessionTimeout=1800000
sessionManager.sessionValidationSchedulerEnabled=true
sessionManager.sessionValidationScheduler=$sessionValidationScheduler;

sessionValidationScheduler:会话验证调度器,sessionManager 默认就是使用 ExecutorServiceSessionValidationScheduler,其使用 JDK 的 ScheduledExecutorService 进行定期调度并验证会话是否过期;
sessionValidationScheduler.interval:设置调度时间间隔,单位毫秒,默认就是 1 小时;
sessionValidationScheduler.sessionManager:设置会话验证调度器进行会话验证时的会话管理器;
sessionManager.globalSessionTimeout:设置全局会话超时时间,默认 30 分钟,即如果 30 分钟内没有访问会话将过期;
sessionManager.sessionValidationSchedulerEnabled:是否开启会话验证器,默认是开启的;
sessionManager.sessionValidationScheduler:设置会话验证调度器,默认就是使用 ExecutorServiceSessionValidationScheduler。

4.2Quartz 会话验证调度器:

sessionValidationScheduler=org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler
sessionValidationScheduler.sessionValidationInterval = 3600000
sessionValidationScheduler.sessionManager=$sessionManager

使用时需要导入 shiro-quartz 依赖:

<dependency>
     <groupId>org.apache.shiro</groupId>
     <artifactId>shiro-quartz</artifactId>
     <version>1.2.2</version>
</dependency>

5.sessionFactory

sessionFactory 是创建会话的工厂,根据相应的 Subject 上下文信息来创建会话;默认提供了 SimpleSessionFactory 用来创建 SimpleSession 会话。
首先自定义一个 Session:

public class OnlineSession extends SimpleSession {
    public static enum OnlineStatus {
        on_line("在线"), hidden("隐身"), force_logout("强制退出");
        private final String info;
        private OnlineStatus(String info) {
            this.info = info;
        }
        public String getInfo() {
            return info;
        }
    }
    private String userAgent; //用户浏览器类型
    private OnlineStatus status = OnlineStatus.on_line; //在线状态
    private String systemHost; //用户登录时系统IP
    //省略其他
};

OnlineSession 用于保存当前登录用户的在线状态,支持如离线等状态的控制。

接着自定义 SessionFactory:

public class OnlineSessionFactory implements SessionFactory {
    @Override
    public Session createSession(SessionContext initData) {
        OnlineSession session = new OnlineSession();
        if (initData != null && initData instanceof WebSessionContext) {
            WebSessionContext sessionContext = (WebSessionContext) initData;
            HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();
            if (request != null) {
                session.setHost(IpUtils.getIpAddr(request));
                session.setUserAgent(request.getHeader("User-Agent"));
                session.setSystemHost(request.getLocalAddr() + ":" + request.getLocalPort());
            }
        }
        return session;
    }
};

根据会话上下文创建相应的 OnlineSession。
最后在 shiro-web.ini 配置文件中配置:

sessionFactory=org.apache.shiro.session.mgt.OnlineSessionFactory
sessionManager.sessionFactory=$sessionFactory

6.会话常用方法总结

1.获得session
Session session = subject.getSession();
2.获取当前会话的唯一标识。
session.getId();
3.获取当前 Subject 的主机地址,该地址是通过 HostAuthenticationToken.getHost() 提供的。
session.getHost();
4.获取 / 设置当前 Session 的过期时间;如果不设置默认是会话管理器的全局过期时间。
session.getTimeout();
session.setTimeout(毫秒);
5.获取会话的启动时间及最后访问时间;如果是 JavaSE 应用需要自己定期调用
session.getStartTimestamp();
session.getLastAccessTime();
6.更新最后访问时间。
session.touch();
7.更新会话最后访问时间及销毁会话
session.stop();
8.设置 / 获取 / 删除会话属性;在整个会话范围内都可以对这些属性进行操作。
session.setAttribute(“key”, “123”);
Assert.assertEquals(“123”, session.getAttribute(“key”));
session.removeAttribute(“key”);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值