Apache Shiro SessionManager
Posted 程序员超时空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apache Shiro SessionManager相关的知识,希望对你有一定的参考价值。
SessionManager是在应用程序中为所有Subject提供Session的管理,包括创建,删除,失效及验证等。同其的核心组件一样,SessionManager也是一个由SecurityManager维护的顶级组件。
在Shiro中默认提供了一个SessionManager的实现DefaultSessionManager。DefaultSessionManager提供一个应用程序所需的所有企业级会话管理。可以在任何应用程序中使用。
如果想自定义一个SessionManager,可在Shiro.ini中配置。例如:
[main]
…
sessionManager=com.foo.my.SessionManagerImplementation
securityManager.sessionManager=$sessionManager
在系统中SessionManager可以通过JavaBean风格的getter/setter方法获取或设置(getSessionManager()/setSessionManager())。
下面介绍默认的SessionManager包含的一些额配置项:
SessionTimeout
默认是30分钟。也就是说,如果任何Session创建后闲置(未被使用,未被更新)的时间超过了30分钟,那么该Session就被认为是过期的,且不允许再被使用。
你可以通过globalSessionTimeout属性来为所有的会话定义默认的超时时间。例如,如果你想超时时间是一个小时而不是30分钟:
[main]
…
#3,600,000milliseconds=1hour
securityManager.sessionManager.globalSessionTimeout=3600000
Per-SessionTimeout
上面的globalSessionTimeout值默认是为所有新建的Session使用的。你可以在每一个会话的基础上控制超时时间通过设置单独的会话超时时间值。与上面的globalSessionTimeout一样,该值以毫秒(不是秒)为时间单位。
SessionListeners
Shiro支持SessionListener概念来允许你对发生的重要会话作出反应。你可以实现SessionListener接口(或扩展易用的SessionListenerAdapter)来与相应的会话操作作出反应。
由于默认的SessionManagersessionListeners属性是一个集合,你可以对SessionManager配置一个或多个listener实现,就像其他在shiro.ini中的集合一样:
[main]
…
aSessionListener=com.foo.my.SessionListener
anotherSessionListener=com.foo.my.OtherSessionListener
securityManager.sessionManager.sessionListeners= a S e s s i o n L i s t e n e r , aSessionListener, aSessionListener,anotherSessionListener,etc.
当任何会话事件发生时,SessionListeners都会被通知——不仅仅是对一个特定的会话。
SessionStorage
每当一个会话被创建或更新时,它的数据需要持久化到一个存储位置以便它能够被稍后的应用程序访问。同样地,当一个会话失效且不再被使用时,它需要从存储中删除以便会话数据存储空间不会被耗尽。SessionManager实现了这些Create/Read/Update/Delete(CRUD)操作做为内部组件,同时,通过SessionDAO反映了数据访问对象(DAO)设计模式。
SessionDAO的作用是你能够通过该接口来与你想要的任何数据存储进行通信。这意味着你的会话数据可以驻留在内存中,文件系统,关系数据库或NoSQL的数据存储,或其他任何你需要的位置。
你可以将任何SessionDAO实现作为一个属性配置在默认的SessionManager实例上。例如,在shiro.ini中:
[main]
…
sessionDAO=com.foo.my.SessionDAO
securityManager.sessionManager.sessionDAO=$sessionDAO
Shiro已经有一些很好的SessionDAO实现,你可以立即使用或实现你需要的子类。
EHCacheSessionDAO
EHCache默认是没有启用的,但如果你不打算实现你自己的SessionDAO,那么强烈地建议你为Shiro的SessionManagerment启用EHCache支持。EHCacheSessionDAO将会在内存中保存会话,并支持若内存不足时可溢出到磁盘。这对确保你在运行时不会随机地“丢失”会话是非常好的。
为所有Shiro的缓存需要使用EHCache:
[main]
sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
securityManager.sessionManager.sessionDAO=$sessionDAO
cacheManager=org.apache.shiro.cache.ehcache.EhcacheManager
securityManager.cacheManager=$cacheManager
最后一行,securityManager.cacheManager=$cacheManager,为所有Shiro的需要配置了一个CacheManager。该CacheManager实例会自动地直接传送到SessionDAO(通过EnterpriseCacheSessionDAO实现CacheManagerAware接口的性质)。
然后,当SessionManager要求EnterpriseCacheSessionDAO去持久化一个Session时,它使用一个EHCache支持的Cache实现去存储Session数据。
CustomSessionIDs
Shiro的SessionDAO在创建一个新的会话时使用一个内置的SessionIdGenerator组件来产生一个新的SessionID。该ID生成后,被指派给新近创建的Session实例,然后该Session通过SessionDAO被保存下来。
默认的SessionIdGenerator是一个JavaUuidSessionIdGenerator,它能产生基于JavaUUIDs的StringIDs。该实现能够支持所有的生产环境。
如果它不符合你的需要,你可以实现SessionIdGenerator接口并在Shiro的SessionDAO实例上配置该实现。例如,在shiro.ini中:
[main]
…
sessionIdGenerator=com.my.session.SessionIdGenerator
securityManager.sessionManager.sessionDAO.sessionIdGenerator=$sessionIdGenerator
SessionValidation&Scheduling
Sessions必须被验证,这样任何无效(过期或停止)的会话能够从会话数据存储中删除。这保证了数据存储不会由于不能再次使用的会话而导致写入超时。
由于性能上的原因,仅仅在Sessions被访问(也就是subject.getSession())时验证它们是否停止或过期。这意味着,如果没有额外的定期验证,Sessionorphans(孤儿)将会开始填充会话数据存储。
会话孤儿,如果它们没有定期清除,将会填充会话数据存储(这是很糟糕的)。因此,为了防止丢放孤儿,SessionManager实现支持SessionValidationScheduler的概念。SessionValidationScheduler负责定期地验证会话以确保它们是否需要清理。
DefaultSessionValidationScheduler
默认可用的SessionValidationScheduler在所有环境中都是ExecutorServiceSessionValidationScheduler,它使用JDKScheduledExecutorService来控制验证频率。
默认地,该实现每小时执行一次验证。你可以通过指定一个新的ExecutorServiceSessionValidationScheduler实例并指定不同的间隔(以毫秒为单位)改变速率来更改验证频率:
[main]
…
sessionValidationScheduler=org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
#Defaultis3,600,000millis=1hour:
sessionValidationScheduler.interval=3600000
securityManager.sessionManager.sessionValidationScheduler=$sessionValidationScheduler
CustomSessionValidationScheduler
如果你希望提供一个自定义的SessionValidationScheduler实现,你可以指定它作为默认的SessionManager实例的一个属性。例如,在shiro.ini中:
[main]
…
sessionValidationScheduler=com.foo.my.SessionValidationScheduler
securityManager.sessionManager.sessionValidationScheduler=$sessionValidationScheduler
DisablingSessionValidation
在某些情况下,你可能希望禁用会话验证项,由于你建立了一个超出了Shiro控制的进程来为你执行验证。例如,也许你正在使用一个企业的Cache并依赖于缓存的TimeToLive设置来自动地去除旧的会话。或者也许你已经制定了一个计划任务来自动清理一个自定义的数据存储。在这些情况下你可以关掉sessionvalidationscheduling:
[main]
…
securityManager.sessionManager.sessionValidationSchedulerEnabled=false
当会话从会话数据存储取回数据时它仍然会被验证,但这会禁用掉Shiro的定期验证。
EnableSessionValidationsomewhere
如果你关闭了Shiro的sessionvalidationscheduler,你必须通过其他的机制(计划任务等)来执行定期的会话验证。这是保证会话孤儿不会填充数据存储的唯一方法。
InvalidSessionDeletion
正如我们上面所说的,进行定期的会话验证主要目的是为了删除任何无效的(过期或停止)会话来确保它们不会填充会话数据存储。
默认地,某些应用程序可能不希望Shiro自动地删除会话。例如,如果一个应用程序已经提供了一个SessionDAO备份数据存储查询,也许是应用程序团队希望旧的或无效的会话在一定的时间内可用。这将允许团队对数据存储运行查询来判断,例如,在上周某个用户创建了多少个会话,或一个用户会话的持续时间,或与之类似报告类型的查询。
在这些情形中,你可以关闭invalidsessiondeletion项。例如,在shiro.ini中:
[main]
…
securityManager.sessionManager.deletInvalidSessions=false
请注意!如果你关闭了它,你得为确保你的会话数据存储不耗尽它的空间复杂。你必须自己从你的数据存储中删除无效的会话!
还要注意,即使你阻止了Shiro删除无效的会话,你仍然应该使用某种会话验证方式——要没通过Shiro的现有验证机制,要么通过一个你自己提供的自定义的机制(见上述的"DisablingSessionValidation"获取更多)。验证机制将会更新你的会话记录以反映无效的状态(例如,什么时候它是无效的,它最后一次被访问是什么时候,等等),即使你在其他的一些时间将手动删除它们。
如果你配置Shiro来让它不会删除无效的会话,你得为确保你的会话数据存储不会耗尽它的空间负责。你必须亲自从你的数据存储删除无效的会话!
另外请注意,禁用会话删除并不等同于禁用sessionvalidationschedule(会话验证调度)。你应该总是使用一个会话验证调度机制——无论是Shiro直接支持或者是你自己的。
以上是关于Apache Shiro SessionManager的主要内容,如果未能解决你的问题,请参考以下文章