前言
shiro 提供了 session 用于保存与用户相关的信息,需要注意到这和 HTTP 的 session 概念是不一样的,它可以运行在没有web环境下。本篇文章会先介绍 Web 环境下的原理,读者有兴趣的话,可以看看在非 Web 环境下的原理。
Session 接口
classDiagram
class Session
<<interface>> Session
class ValidatingSession
<<interface>> ValidatingSession
Session <|-- ValidatingSession
class SimpleSession
ValidatingSession <|-- SimpleSession
class DelegatingSession
Session <|-- DelegatingSession
class HttpServletSession
Session <|-- HttpServletSession
class ProxiedSession
Session <|-- ProxiedSession
Session
定义了主要接口,支持设置时间有效期,存储等。
|
|
HttpServletSession
实现了 http 的 session,运行在 web 环境。
DelegatingSession
支持本地管理 session,运行在非 web 环境。
ProxiedSession
只是Session
的代理类。
SimpleSession
只是简单的Session
实现类。
Session 管理
session 管理分为两类,非 Web 环境和 Web 环境。它负责 session 的创建,查找,删除等管理操作,由SessionManager
接口表示。
SessionManager 接口
SessionManager
只有两个方法,创建和查找 session。通过这两个方法的声明,可以看到多个概念的联系。
|
|
上述方法涉及到了 Session
,SessionContext
,SessionKey
和SessionManager
四种概念,这里先简单介绍下它们,
Session
存储了用户的相关信息SessionContext
用作初始化Session
实例SessionKey
是Session
实例的 id,用于查找SessionManager
管理着多个Session
SessionManager 类图
session 管理根据使用环境分为 HTTP 和 非 HTTP 两类。下图中左边的部分是使用本地 session 管理,在 Web 环境和非 Web 环境下都可以试用。右边的是使用Servlet
自带的 session 管理,只能在 Web 环境下使用。
classDiagram
class SessionManager
<<interface>> SessionManager
class NativeSessionManager
<<interface>> NativeSessionManager
SessionManager <|-- NativeSessionManager
class AbstractSessionManager
<<abstract>> AbstractSessionManager
SessionManager <|-- AbstractSessionManager
class ValidatingSessionManager
<<interface>> ValidatingSessionManager
SessionManager <|-- ValidatingSessionManager
class AbstractNativeSessionManager
<<abstract>> AbstractNativeSessionManager
class AbstractValidatingSessionManager
<<abstract>> AbstractValidatingSessionManager
AbstractSessionManager <|-- AbstractNativeSessionManager
AbstractNativeSessionManager <|-- AbstractValidatingSessionManager
NativeSessionManager <|-- AbstractNativeSessionManager
ValidatingSessionManager <|-- AbstractValidatingSessionManager
class DefaultSessionManager
AbstractValidatingSessionManager <|-- DefaultSessionManager
AbstractNativeSessionManager <|-- AbstractValidatingSessionManager
ValidatingSessionManager <|-- AbstractValidatingSessionManager
class WebSessionManager
<<interface>> WebSessionManager
SessionManager <|-- WebSessionManager
WebSessionManager <|-- ServletContainerSessionManager
class DefaultWebSessionManager
DefaultSessionManager <|-- DefaultWebSessionManager
WebSessionManager <|-- DefaultWebSessionManager
NativeSessionManager
定义了本地 session 管理的接口,也就是说它可以存在非 web 环境下。
DefaultSessionManager
是用于非 Web 环境下, 默认的管理器。
DefaultWebSessionManager
是 shrio 支持用于 Web 环境下,只不过使用了自己的 session 管理。
ServletContainerSessionManager
是基于 spring web 实现的,只能用于 Web 环境下,它只是简单的封装了Serlvet
相关功能。
Web 环境
因为 Web 的场景会非常普遍,而且实现也比较简单,所以会先讲解这部分。ServletContainerSessionManager
类实现了SessionManager
接口,下面是它的代码
|
|
可以看到,它只是简单的调用了HttpServletRequest
相关的方法,创建了HttpServletSession
实例。HttpServletSession
也只是简单的包装了一下HTTPSession
。
|
|
非 Web 环境
DefaultSessionManager
是非 Web 环境下默认的 session 管理器。我们来看看它的实现原理,因为它继承了AbstractNativeSessionManager
类,所以真正的创建 session 实例由doCreateSession
方法负责。从下面的代码可以看到,session的创建是有工厂类SessionFactory
负责,并且创建后还会将其持久化。
|
|
同样根据 sessionId 查找 session 的方法,最终由retrieveSession
实现。可以看到session的查找最终是由SessionDAO
负责。
|
|
Session 实例化
上面涉及到了SessionFactory
工厂类,用作创建 session。接下来就讲讲它的原理。
SessionFactory 工厂类
SessionFactory
接口定义了创建 Session 的方法createSession
,其中参数SessionContext
是用作初始化的。
|
|
目前只有SimpleSessionFactory
类实现了该接口,它的实现非常简单
|
|
初始化参数SessionContext
SessionContext
的相关类图如下所示,虽然比较多,但是原理很简单。
classDiagram
class Map
<<interface>> Map
class SessionContext
<<interface>> SessionContext
class MapContext
Map <|-- SessionContext
Map <|-- MapContext
class RequestPairSource
<<interface>> RequestPairSource
class WebSessionContext
<<interface>> WebSessionContext
SessionContext <|-- WebSessionContext
RequestPairSource <|-- WebSessionContext
class DefaultSessionContext
MapContext <|-- DefaultSessionContext
SessionContext <|-- DefaultSessionContext
class DefaultWebSessionContext
DefaultSessionContext <|-- DefaultWebSessionContext
WebSessionContext <|-- DefaultWebSessionContext
SessionContext
继承 Map
接口,并且定义了 host 和 sessionId 两个属性的操作方法。
|
|
DefaultSessionContext
实现了默认的SessionContext
接口。
DefaultWebSessionContext
在它基础之上,添加了获取ServletRequest
和ServletResponse
实例的方法。
Session 持久化
SessionDAO
定义了 session 增删改查接口,如下所示:
|
|
它的子类图如下所示:
classDiagram
class SessionDAO
<<interface>> SessionDAO
class AbstractSessionDAO
<<abstract>> AbstractSessionDAO
SessionDAO <|-- AbstractSessionDAO
class CachingSessionDAO
<<abstract>> CachingSessionDAO
AbstractSessionDAO <|-- CachingSessionDAO
class MemorySessionDAO
AbstractSessionDAO <|-- MemorySessionDAO
class EnterpriseCacheSessionDAO
CachingSessionDAO <|-- EnterpriseCacheSessionDAO
AbstractSessionDAO
实现了SessionDAO
接口,并且定义了doCreate
接口,子类需要实现它并且返回 SessionId
。
MemorySessionDAO
使用了 ConcurrentMap
来保存 session。
CachingSessionDAO
实现了session缓存,用户可以集成CacheManager
实现自定义的缓存。
当持久化化 session 的时候,SessionDAO
会使用SessionIdGenerator
接口生成唯一的 SessionId
。
classDiagram
class SessionIdGenerator
<<interface>> SessionIdGenerator
class RandomSessionIdGenerator
class JavaUuidSessionIdGenerator
SessionIdGenerator <|-- RandomSessionIdGenerator
SessionIdGenerator <|-- JavaUuidSessionIdGenerator
RandomSessionIdGenerator
会生成随机的 sessionId,JavaUuidSessionIdGenerator
会生成 uuid。
Session 集成
我们再回到DefaultSecurityManager
类,看看它是如何集成Session
的。SessionsSecurityManager
是它的父类,它默认使用DefaultSessionManager
实现,实现了 session 管理。
|
|