注意:阅读本篇需要上一篇的相关代码与设置
会话过期时间设置
默认会话管理器设置
我们的Demo1中的DefaultSecurityManager默认使用的是DefaultSessionManager,我们可以使用如下方式来设置会话过期时间
DefaultSessionManager sessionManager = new DefaultSessionManager();
sessionManager.setGlobalSessionTimeout(1000);// 单位毫秒
web应用设置
web应用中(参考上一篇springboot的整合代码)我们使用的是DefaultWebSecurityManager,其使用的默认SessionManager是ServletContainerSessionManager,此将session的管理委派给运行时Servlet容器(如:tomcat、jetty、jboss等,我们上一篇是springboot自带的tomcat)。其会话过期的设置跟Servlet容器一致。我们可以如下设置我们的上一篇示例的会话过期时间:
# application.properties文件设置会话过期时间(单位s秒、m分)
server.servlet.session.timeout=30s
其他情况(直接部署到容器,请自行查阅对应容器的配置)
使用DefaultWebSessionManager替代web默认的会话管理器
在ShiroConfig配置代码中修改代码如下:
@Bean
public SecurityManager securityManager(Realm realm) {
// 注意:这里的DefaultWebSecurityManager和我们之前的Demo使用的DefaultSecurityManager有区别
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 修改web环境下的默认sessionManager
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(5*60*1000);// 5分钟
securityManager.setSessionManager(sessionManager);
log.error("shiro SessionManager:{}",securityManager.getSessionManager());
securityManager.setRealm(realm);
return securityManager;
}
这里我们设置的过期时间为5分钟,我们上面设置的容器session过期时间为30s。你尝试一下就会发现,30s到时候session并没有过期,5分钟后才会过期。
这意味着我们通过DefaultWebSessionManager来实现sessionManager可以避免依赖容器的session管理,来提高我们代码的可移植性。
会话监听
sessionManager默认会话监听器列表为空,我们可以实现SessionListener来监听会话。SessionListener接口的定义如下:
package org.apache.shiro.session;
public interface SessionListener {
void onStart(Session var1);
void onStop(Session var1);
void onExpiration(Session var1);
}
什么简单不是吗,我想不用多做解释。
我们自定义监听器后,通过sessionManager对象即可设置加入我们自定义的监听器。
会话的存储
- 每当创建或更新会话时,其数据都需要保存到存储位置,以便应用程序稍后可以访问它。
- 当会话无效或长时间不使用时,需要将其从存储中删除
- 创建/读取/更新/删除(CRUD)操作会话的shiro组件为SessionDAO,通过实现SessionDAO我们可以将会话存储到任意我们想要的地方(数据库、本地缓存、EHCache(shiro有现成的实现,引入shiro-ehcache-.jar即可,本教程不做讲解)、redis缓存等)
SessionDAO接口定义如下:
package org.apache.shiro.session.mgt.eis;
import java.io.Serializable;
import java.util.Collection;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
public interface SessionDAO {
// 创建session
Serializable create(Session var1);
// 读取session
Session readSession(Serializable var1) throws UnknownSessionException;
// 更新session
void update(Session var1) throws UnknownSessionException;
// 删除session
void delete(Session var1);
// 当前活跃的session列表
Collection<Session> getActiveSessions();
}
SessionDAO的继承结构图如下
DefaultSessionManager默认使用的是MemorySessionDAO(SessionDAO是SessionManager的一个属性),内部通过ConcurrentHashMap实现内存存储。也就是说,我们的代码目前为止,尚不支持集群下的session认证,因为每个session是存在单机内存中的。此问题以及自定义SessionDAO我们后面再提。
自定义会话ID
每当创建新会话时,Shiro的SessionDAO实现都使用内部SessionIdGenerator组件来生成新的Session ID。生成ID后,将其分配给新创建的Session实例。
默认SessionIdGenerator值为a JavaUuidSessionIdGenerator,它String基于Java生成ID UUIDs。
我们也可以自定义SessionIdGenerator,只需实现SessionIdGenerator接口即可。
SessionIdGenerator继承关系
SessionIdGenerator接口定义如下
package org.apache.shiro.session.mgt.eis;
import java.io.Serializable;
import org.apache.shiro.session.Session;
public interface SessionIdGenerator {
Serializable generateId(Session var1);
}
JavaUuidSessionIdGenerator实现如下
package org.apache.shiro.session.mgt.eis;
import java.io.Serializable;
import java.util.UUID;
import org.apache.shiro.session.Session;
public class JavaUuidSessionIdGenerator implements SessionIdGenerator {
public JavaUuidSessionIdGenerator() {
}
public Serializable generateId(Session session) {
return UUID.randomUUID().toString();
}
}
SessionIdGenerator是对应的SessionDAO的一个属性,如果UUID无法满足你的需求,你可以自定义SessionIdGenerator。
会话过期验证
正常情况下,如果用户操作了logout,会话将会清除,每次会话操作将会更新会话。但特殊情况下,如:用户登录操作之后,没有logout而长时间处于会话中,期间没有任何的主动操作,到了会话过期时间之后,由于没有主动的操作,会话将不会删除。但如果不定期删除无效的、长时间不操作的会话,我们的会话存储空间将会占满。在shiro中SessionValidationScheduler负责定期验证会话,以确保在必要时进行清理。
SessionValidationScheduler默认实现是ExecutorServiceSessionValidationScheduler
默认情况下,此实现将每小时执行一次验证。您可以通过指定的新实例ExecutorServiceSessionValidationScheduler并指定其他间隔(以毫秒为单位)来更改验证发生的速率
[main]
...
sessionValidationScheduler = org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
# Default is 3,600,000 millis = 1 hour:
sessionValidationScheduler.interval = 3600000
securityManager.sessionManager.sessionValidationScheduler = $sessionValidationScheduler
禁用会话验证
在某些情况下,您可能希望完全禁用会话验证,因为您已经在Shiro的控制范围之外设置了一个过程来为您执行验证。例如,也许您正在使用企业缓存,并依靠缓存的“生存时间”设置来自动清除旧会话。或者,也许您已经设置了cron作业来自动清除自定义数据存储。在这些情况下,您可以关闭会话验证计划:
[main]
...
securityManager.sessionManager.sessionValidationSchedulerEnabled = false
禁用无效的会话删除
某些应用程序可能不希望Shiro自动删除会话。例如,如果某个应用程序提供了一个SessionDAO支持可查询数据存储的,则应用程序团队可能希望在某个时间段内可以使用旧的或无效的会话。这将允许团队对数据存储区运行查询,以查看例如用户在上周创建了多少会话,或者用户会话的平均持续时间,或类似的报告类型查询。
[main]
...
securityManager.sessionManager.deleteInvalidSessions = false
注意:如果禁用无效的会话删除,可能造成存储session的空间占满的问题。请谨慎使用改功能。