我們先來看一下shiro中關於Session和Session Manager的類圖。


如上圖所示,shiro自己定義了一個新的Session接口,用於統一操作接口,並通過SessionManager實現Session管理。
其中的3個實現類HttpServletSession,SimpleSession和StoppingAwareProxiedSession是我們經常需要打交道的。
HttpServletSession
首先,我們來看看org.apache.shiro.web.session.HttpServletSession的實現。
public HttpServletSession(HttpSession httpSession, String host) {
if (httpSession == null) {
String msg = "HttpSession constructor argument cannot be null.";
throw new IllegalArgumentException(msg);
}
if (httpSession instanceof ShiroHttpSession) {
String msg = "HttpSession constructor argument cannot be an instance of ShiroHttpSession. This " +
"is enforced to prevent circular dependencies and infinite loops.";
throw new IllegalArgumentException(msg);
}
this.httpSession = httpSession;
if (StringUtils.hasText(host)) {
setHost(host);
}
}
顯然,HttpServletSession只是簡單對javax.servlet.http.HttpSession進行了封裝,即:
在Web應用程序中,所有對Session相關的操作最終都是對javax.servlet.http.HttpSession進行的。

通過對上述Subject.login()的時序圖分析可以知道:
在Web應用程序中,Shiro確實是通過ServletContainerSessionManager獲取到容器創建的HttpSession再封裝為HttpServletSession的。
也就是說,Subject.login()登錄成功后用戶的認證信息實際上是保存在HttpSession中的。如果此時Web應用程序部署了多實例,必須要進行Session同步。
我們知道,SecurityManager是整個Shiro框架的核心控制器,在SpringMVC中集成Shiro時,就需要明確配置對應的SecurityManager。
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="myRealm" />
</bean>
而在org.apache.shiro.web.mgt.DefaultWebSecurityManager的實現中,使用的SessionManager就是ServletContainerSessionManager。
public DefaultWebSecurityManager() {
super();
((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());
this.sessionMode = HTTP_SESSION_MODE;
setSubjectFactory(new DefaultWebSubjectFactory());
setRememberMeManager(new CookieRememberMeManager());
setSessionManager(new ServletContainerSessionManager()); // 配置Session Manager
}
SimpleSession
shiro具備完善的Session管理機制,當在命令行程序中使用Shiro框架時,同樣可以執行與Web應用程序一樣的Session操作。
此時,Shiro實際上使用SimpleSession實現。
StoppingAwareProxiedSession
實際上,StoppingAwareProxiedSession僅僅是一個Session包裝類,即:
無論是HttpServletSession還是SimpleSession,在執行Subject.login()時保存到Subject中的Session都是StoppingAwareProxiedSession對象。
private class StoppingAwareProxiedSession extends ProxiedSession {
private final DelegatingSubject owner;
private StoppingAwareProxiedSession(Session target, DelegatingSubject owningSubject) {
super(target);
owner = owningSubject;
}
public void stop() throws InvalidSessionException {
super.stop();
owner.sessionStopped();
}
}

