Shiro中的Session管理
Shiro中Session有兩個來源:
- 獲取Servlet容器(如tomcat)的session。
- 使用自己的Session管理機制。
當我們在非web環境下(是的,Shiro可以在非web環境下身份驗證),肯定是第二種。
在web環境下的話,就看SessionManager的具體類型了。
我們常用的安全管理器是DefaultWebSecurityManager.繼承結構如下。

在它的父類SessionsSecurityManager中包含sessionManager屬性。默認是DefaultSessionManager。
通過設置為DefaultWebSessionManager可以把session讓shiro來控制。

具體分析如下:
我們都知道shiro通過filter來攔截更改請求。
filter的繼承關系如下圖:

OncePerRequestFilter會調用doFilter方法,這個方法會調用doFilterInternal。
AbstractShiroFilter子類實現了doFilterInternal這個方法。這個方法繼續調用doFilterInternal ->prepareServletRequest -> wrapServletRequest。 wrapServletRequest這個方法,會根據域中securityManager的isHttpSessionMode方法來判斷是否采用servlet容器的session。(true:使用servlet容器的session,false:采用自定義session)。
public abstract class AbstractShiroFilter extends OncePerRequestFilter {
protected ServletRequest wrapServletRequest(HttpServletRequest orig) {
return new ShiroHttpServletRequest(orig, getServletContext(), isHttpSessions());
}
//......
}
public class ShiroHttpServletRequest extends HttpServletRequestWrapper {
public HttpSession getSession(boolean create) {
HttpSession httpSession;
if (isHttpSessions()) {
httpSession = super.getSession(false);
if (httpSession == null && create) {
//Shiro 1.2: assert that creation is enabled (SHIRO-266):
if (WebUtils._isSessionCreationEnabled(this)) {
httpSession = super.getSession(create);
} else {
throw newNoSessionCreationException();
}
}
} else {
boolean existing = getSubject().getSession(false) != null;
if (this.session == null || !existing) {
Session shiroSession = getSubject().getSession(create);
if (shiroSession != null) {
this.session = new ShiroHttpSession(shiroSession, this, this.servletContext);
if (!existing) {
setAttribute(REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
}
} else if (this.session != null) {
this.session = null;
}
}
httpSession = this.session;
}
return httpSession;
}
//......
}
可以看出,如果isHttpSessionMode結果為真,那么ShiroHttpServletRequest在getSession時會調用父類(HttpServletRequest)的結果,也就是servlet容器的結果。
但如果為假,則會new ShiroHttpSession來創建shiro自定義的session。
那么isHttpSessionMode的結果是怎么來的呢?
實現了這個方法的類是DefaultWebSessionManager,它的isHttpSessionMode方法中,會判斷它類中的字段sessionManager。如果sessionManager是WebSessionManager的子類,同時它的isServletContainerSessions方法返回真,那么整個方法就返回真。
public class DefaultWebSecurityManager extends DefaultSecurityManager implements WebSecurityManager {
public boolean isHttpSessionMode() {
SessionManager sessionManager = getSessionManager();
return sessionManager instanceof WebSessionManager && ((WebSessionManager)sessionManager).isServletContainerSessions();
}
public SessionManager getSessionManager() {
return this.sessionManager;
}
//.....
}
(還是挺繞的)
相關文章:
