SessionManager负责管理shiro自己封装的session的生命周期。
为什么shiro要自己封装session?
1.可以为任意应用提供session支持,不依赖于底层容器
2.简单扩容session管理容器,可以实现任何数据源(redis,ehcache)来管理session,而不必担心jvm内存溢出
public interface SessionManager {
//根据指定的上下文SessionContext交由SessionFactory初始化个新的session
Session start(SessionContext context);
//根据指定的上下文信息(SessonId..)获取一个session,如果不存在返回null,如果存在但是失效,则抛出异常SessionException
Session getSession(SessionKey key) throws SessionException;
}
2.AbstractSessionManager
/**AbstractSessionManager是SessionManager的顶层抽象类,主要提供Session存活时间管理的支持,
默认session存活时间是30分钟
deprecate this class (see SHIRO-240):
这个类主要为子类提供一个常用的属性“globalSessionTimeout”的支持,最初设计是为ServletContainerSessionManager
和AbstractNativeSessionManager提供session存活时间管理支持,但是ServletContainerSessionManager的实现并没有
使用该“globalSessionTimeout”,这意味着只有AbstractNativeSessionManager需要使用。所以该类没有存在必要了。
https://issues.apache.org/jira/browse/SHIRO-240
**/
public abstract class AbstractSessionManager implements SessionManager {
protected static final long MILLIS_PER_SECOND = 1000;
protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
/**
* Default main session timeout value, equal to {@code 30} minutes.
*/
public static final long DEFAULT_GLOBAL_SESSION_TIMEOUT = 30 * MILLIS_PER_MINUTE;
//默认为30分钟
private long globalSessionTimeout = DEFAULT_GLOBAL_SESSION_TIMEOUT;
public AbstractSessionManager() {
}
public long getGlobalSessionTimeout() {
return this.globalSessionTimeout;
}
//覆盖默认session存活时间30分钟
public void setGlobalSessionTimeout(long globalSessionTimeout) {
this.globalSessionTimeout = globalSessionTimeout;
}
}
3.AbstractNativeSessionManager
/**
该类基础父类AbstractSessionManager和实现NativeSessionManager接口(session操作方法规范),提供
session的start、stop、Expiration状态的触发通知。
**/
public abstract class AbstractNativeSessionManager extends AbstractSessionManager implements NativeSessionManager {
private static final Logger log = LoggerFactory.getLogger(AbstractSessionManager.class);
//SESSION状态的触发通知(start、stop、Expiration)
private Collection listeners;
public AbstractNativeSessionManager() {
this.listeners = new ArrayList();
}
public void setSessionListeners(Collection listeners) {
this.listeners = listeners != null ? listeners : new ArrayList();
}
@SuppressWarnings({"UnusedDeclaration"})
public Collection getSessionListeners() {
return this.listeners;
}
//实现SessionManager接口的start方法
public Session start(SessionContext context) {
//创建session
Session session = createSession(context);
//设置session过期时间
applyGlobalSessionTimeout(session);
//模板方法,子类对创建session后作出反应
onStart(session, context);
//创建session成功,迭代SessionListener执行onStart通知
notifyStart(session);
//返回一个包装过客户端层session,
return createExposedSession(session, context);
}
//根据上下文SessionContext创建Session,返回的session需要持久化状态,方便以后获取使用
protected abstract Session createSession(SessionContext context) throws AuthorizationException;
//设置session过期时间
protected void applyGlobalSessionTimeout(Session session) {
session.setTimeout(getGlobalSessionTimeout());
//session改变模板方法,子类对session改变作出反应。如:保存改变后的session
onChange(session);
}
//模板方法:子类对session start后作出反应
protected void onStart(Session session, SessionContext context) {
}
//根据sessionKey获取Session
public Session getSession(SessionKey key) throws SessionException {
Session session = lookupSession(key);
return session != null ? createExposedSession(session, key) : null;
}
private Session lookupSession(SessionKey key) throws SessionException {
if (key == null) {
throw new NullPointerException("SessionKey argument cannot be null.");
}
return doGetSession(key);
}
//获取session,如果session为null则抛异常UnknownSessionException
private Session lookupRequiredSession(SessionKey key) throws SessionException {
Session session = lookupSession(key);
if (session == null) {
String msg = "Unable to locate required Session instance based on SessionKey [" + key + "].";
throw new UnknownSessionException(msg);
}
return session;
}
//子类实现抽象方法根据sessonKey获取session
protected abstract Session doGetSession(SessionKey key) throws InvalidSessionException;
//封装返回客户端层session
protected Session createExposedSession(Session session, SessionContext context) {
return new DelegatingSession(this, new DefaultSessionKey(session.getId()));
}
//封装返回客户端层session
protected Session createExposedSession(Session session, SessionKey key) {
return new DelegatingSession(this, new DefaultSessionKey(session.getId()));
}
//当session过期或者停止时,需要调用通知。再调用通知前先包装下session为不可变session,防止SessionListener修改
protected Session beforeInvalidNotification(Session session) {
//ImmutableProxiedSession的实现即对session凡是有修改意向的方法进行重写为抛异常。
return new ImmutableProxiedSession(session);
}
//session start创建后调用SessionListener的onStart通知
protected void notifyStart(Session session) {
for (SessionListener listener : this.listeners) {
listener.onStart(session);
}
}
//session stop后调用SessionListener的onStop通知
protected void notifyStop(Session session) {
Session forNotification = beforeInvalidNotification(session);
for (SessionListener listener : this.listeners) {
listener.onStop(forNotification);
}
}
//session Expiration后调用SessionListener的onExpiration通知
protected void notifyExpiration(Session session) {
Session forNotification = beforeInvalidNotification(session);
for (SessionListener listener : this.listeners) {
listener.onExpiration(forNotification);
}
}
//根据sessionKey 获取session的创建时间
public Date getStartTimestamp(SessionKey key) {
return lookupRequiredSession(key).getStartTimestamp();
}
//根据sessionKey 获取session最后访问时间
public Date getLastAccessTime(SessionKey key) {
return lookupRequiredSession(key).getLastAccessTime();
}
//根据sessionKey 获取session过期时间. 负数:则永远不过期 正数:毫秒内有效
public long getTimeout(SessionKey key) throws InvalidSessionException {
return lookupRequiredSession(key).getTimeout();
}
//根据sessionKey设置session过期时间
public void setTimeout(SessionKey key, long maxIdleTimeInMillis) throws InvalidSessionException {
Session s = lookupRequiredSession(key);
s.setTimeout(maxIdleTimeInMillis);
onChange(s);
}
//根据sessionKey修改session最后访问时间
public void touch(SessionKey key) throws InvalidSessionException {
Session s = lookupRequiredSession(key);
s.touch();
onChange(s);
}
//根据sessionKey获取session 访问IP..
public String getHost(SessionKey key) {
return lookupRequiredSession(key).getHost();
}
//根据sessionKey 获取session里的设置的属性
public Collection
4.AbstractValidatingSessionManager
/**
AbstractValidatingSessionManager继承于AbstractNativeSessionManager且实现了ValidatingSessionManager接口,该抽象类
主要提供session验证和过期session检测。
**/
public abstract class AbstractValidatingSessionManager extends AbstractNativeSessionManager
implements ValidatingSessionManager, Destroyable {
private static final Logger log = LoggerFactory.getLogger(AbstractValidatingSessionManager.class);
//默认每小时检测一次
public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = MILLIS_PER_HOUR;
//是否开启session验证检测
protected boolean sessionValidationSchedulerEnabled;
//该接口主要代理SessionManager.validateSessions()方法,定时对session验证检测。如:过期的session则销毁等
protected SessionValidationScheduler sessionValidationScheduler;
//该属性是定义多长时间检测一次,这个值需要根据用户的实际情况来选择,定义的太小,则检测频繁对系统性能有影响.
protected long sessionValidationInterval;
public AbstractValidatingSessionManager() {
//默认开启检测
this.sessionValidationSchedulerEnabled = true;
//默认每小时检测一次
this.sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;
}
public boolean isSessionValidationSchedulerEnabled() {
return sessionValidationSchedulerEnabled;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setSessionValidationSchedulerEnabled(boolean sessionValidationSchedulerEnabled) {
this.sessionValidationSchedulerEnabled = sessionValidationSchedulerEnabled;
}
public void setSessionValidationScheduler(SessionValidationScheduler sessionValidationScheduler) {
this.sessionValidationScheduler = sessionValidationScheduler;
}
public SessionValidationScheduler getSessionValidationScheduler() {
return sessionValidationScheduler;
}
//确保sessionValidation功能是开启的且有效的
private void enableSessionValidationIfNecessary() {
SessionValidationScheduler scheduler = getSessionValidationScheduler();
//如果该类允许sessionValidation功能开启且scheduler无效的,则执行enableSessionValidation创建SessionValidationScheduler
if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {
enableSessionValidation();
}
}
public void setSessionValidationInterval(long sessionValidationInterval) {
this.sessionValidationInterval = sessionValidationInterval;
}
public long getSessionValidationInterval() {
return sessionValidationInterval;
}
@Override
protected final Session doGetSession(final SessionKey key) throws InvalidSessionException {
//这里我觉得会有并发问题,导致创建scheduler多次,且实现方式有问题,为什么要在使用session的地方确保每次都开启呢?
enableSessionValidationIfNecessary();
log.trace("Attempting to retrieve session with key {}", key);
//根据sessionKey获取session
Session s = retrieveSession(key);
//如果session不为null,则检测session是否有效的
if (s != null) {
validate(s, key);
}
return s;
}
//根据sessionKey获取session
protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException;
protected Session createSession(SessionContext context) throws AuthorizationException {
enableSessionValidationIfNecessary();
return doCreateSession(context);
}
//子类实现创建session
protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException;
//验证session
protected void validate(Session session, SessionKey key) throws InvalidSessionException {
try {
doValidate(session);
} catch (ExpiredSessionException ese) {
//session过期异常
onExpiration(session, ese, key);
throw ese;
} catch (InvalidSessionException ise) {
//session停止无效异常
onInvalidation(session, ise, key);
throw ise;
}
}
//处理过期session
protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
log.trace("Session with id [{}] has expired.", s.getId());
try {
onExpiration(s);
//session过期通知
notifyExpiration(s);
} finally {
//最后处理过期session。如:删除session
afterExpired(s);
}
}
protected void onExpiration(Session session) {
onChange(session);
}
protected void afterExpired(Session session) {
}
//处理无效session
protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey key) {
if (ise instanceof ExpiredSessionException) {
onExpiration(s, (ExpiredSessionException) ise, key);
return;
}
log.trace("Session with id [{}] is invalid.", s.getId());
try {
//对停止session作出处理:如:设置停止时间为最后访问时间
onStop(s);
//调用session停止通知
notifyStop(s);
} finally {
//session停止后作出处理,如:删除session
afterStopped(s);
}
}
//执行session的验证机制,实则交由session自己的validate();
protected void doValidate(Session session) throws InvalidSessionException {
if (session instanceof ValidatingSession) {
((ValidatingSession) session).validate();
} else {
String msg = "The " + getClass().getName() + " implementation only supports validating " +
"Session implementations of the " + ValidatingSession.class.getName() + " interface. " +
"Please either implement this interface in your session implementation or override the " +
AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
throw new IllegalStateException(msg);
}
}
/**
* 这我也搞不懂干嘛的。。
* Subclass template hook in case per-session timeout is not based on
* {@link org.apache.shiro.session.Session#getTimeout()}.
*
* This implementation merely returns {@link org.apache.shiro.session.Session#getTimeout()}
*
* @param session the session for which to determine session timeout.
* @return the time in milliseconds the specified session may remain idle before expiring.
*/
protected long getTimeout(Session session) {
return session.getTimeout();
}
//确保sessionValidation有效
protected void enableSessionValidation() {
SessionValidationScheduler scheduler = getSessionValidationScheduler();
if (scheduler == null) {
//如果为null。则创建个新的SessionValidationScheduler且设置到this.SessionValidationScheduler
scheduler = createSessionValidationScheduler();
setSessionValidationScheduler(scheduler);
}
if (log.isInfoEnabled()) {
log.info("Enabling session validation scheduler...");
}
//启动SessionValidationScheduler里的验证机制
scheduler.enableSessionValidation();
//开启session验证后可以作出你的逻辑处理。目前shiro没有实现任何功能,你可根据你需求来决定。
//如:记录每次开启时间
afterSessionValidationEnabled();
}
//创建SessionValidationScheduler
protected SessionValidationScheduler createSessionValidationScheduler() {
ExecutorServiceSessionValidationScheduler scheduler;
if (log.isDebugEnabled()) {
log.debug("No sessionValidationScheduler set. Attempting to create default instance.");
}
//创建ExecutorServiceSessionValidationScheduler且设置本实例进去,因为scheduler需要代理本实例的validateSessions
scheduler = new ExecutorServiceSessionValidationScheduler(this);
scheduler.setInterval(getSessionValidationInterval());
if (log.isTraceEnabled()) {
log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "].");
}
return scheduler;
}
protected void afterSessionValidationEnabled() {
}
//销毁SessionValidation
protected void disableSessionValidation() {
beforeSessionValidationDisabled();
SessionValidationScheduler scheduler = getSessionValidationScheduler();
if (scheduler != null) {
try {
//先执行SessionValidationScheduler自己的disableSessionValidation
scheduler.disableSessionValidation();
if (log.isInfoEnabled()) {
log.info("Disabled session validation scheduler.");
}
} catch (Exception e) {
if (log.isDebugEnabled()) {
String msg = "Unable to disable SessionValidationScheduler. Ignoring (shutting down)...";
log.debug(msg, e);
}
}
LifecycleUtils.destroy(scheduler);
//设置this.SessionValidationScheduler为null
setSessionValidationScheduler(null);
}
}
protected void beforeSessionValidationDisabled() {
}
public void destroy() {
disableSessionValidation();
}
//所有session真正的检测验证逻辑
public void validateSessions() {
if (log.isInfoEnabled()) {
log.info("Validating all active sessions...");
}
//用来记录当前这一批次检验到session过期或者无效的总数
int invalidCount = 0;
//获取sessionDAO中当前所有存在session,包括无效、过期的
Collection activeSessions = getActiveSessions();
/**
当你用户量如果非常大时候,假如有1亿个session,那么迭代会花很长时间且在这一阶段里会影响性能.可以分批次
**/
if (activeSessions != null && !activeSessions.isEmpty()) {
for (Session s : activeSessions) {
try {
//simulate a lookup key to satisfy the method signature.
//this could probably stand to be cleaned up in future versions:
SessionKey key = new DefaultSessionKey(s.getId());
//验证session
validate(s, key);
} catch (InvalidSessionException e) {
if (log.isDebugEnabled()) {
boolean expired = (e instanceof ExpiredSessionException);
String msg = "Invalidated session with id [" + s.getId() + "]" +
(expired ? " (expired)" : " (stopped)");
log.debug(msg);
}
invalidCount++;
}
}
}
if (log.isInfoEnabled()) {
String msg = "Finished session validation.";
if (invalidCount > 0) {
msg += " [" + invalidCount + "] sessions were stopped.";
} else {
msg += " No sessions were stopped.";
}
log.info(msg);
}
}
//获取sessionDAO中当前所有存在session,包括无效、过期的
protected abstract Collection getActiveSessions();
}
5.DefaultSessionManager
/**
DefaultSessionManager继承AbstractValidatingSessionManager且实现CacheManagerAware接口,
该具体实现类实现缓存接口CacheManagerAware只是为了让SessionDAO使用。
所有关于session的状态的改变都是交由DefaultSessionManager的sessionDAO处理。
**/
public class DefaultSessionManager extends AbstractValidatingSessionManager implements CacheManagerAware {
private static final Logger log = LoggerFactory.getLogger(DefaultSessionManager.class);
//SessionFactory用来根据上下文创建新session
private SessionFactory sessionFactory;
//SessionDAO实现了缓存机制,所以用户只要实现第三方缓存,不依赖于JVM,就不必担心session过多导致内存溢出
protected SessionDAO sessionDAO; //todo - move SessionDAO up to AbstractValidatingSessionManager?
//缓存管理器
private CacheManager cacheManager;
/**
是否删除session,如果session过期或者无效后。但是有些系统需要获取及时过期或者无效的SESSION。
默认为true。如果设置为false,需要用户自己有办法在外部去管理过期或者无效session
**/
private boolean deleteInvalidSessions;
public DefaultSessionManager() {
this.deleteInvalidSessions = true;
this.sessionFactory = new SimpleSessionFactory();
this.sessionDAO = new MemorySessionDAO();
}
public void setSessionDAO(SessionDAO sessionDAO) {
this.sessionDAO = sessionDAO;
//设置CacheManager到SessionDAO
applyCacheManagerToSessionDAO();
}
public SessionDAO getSessionDAO() {
return this.sessionDAO;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
//session过期或者无效后是否删除
public boolean isDeleteInvalidSessions() {
return deleteInvalidSessions;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setDeleteInvalidSessions(boolean deleteInvalidSessions) {
this.deleteInvalidSessions = deleteInvalidSessions;
}
//设置缓存管理器
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
//设置缓存管理器到SessionDAO
applyCacheManagerToSessionDAO();
}
private void applyCacheManagerToSessionDAO() {
//如果缓存管理器和SessionDAO都不null,且SessionDAO实现了CacheManagerAware,则设置CacheManager到SessionDAO
if (this.cacheManager != null && this.sessionDAO != null && this.sessionDAO instanceof CacheManagerAware) {
((CacheManagerAware) this.sessionDAO).setCacheManager(this.cacheManager);
}
}
//根据session上下文SessionContext创建Session
protected Session doCreateSession(SessionContext context) {
//调用SessionFactory创建session
Session s = newSessionInstance(context);
if (log.isTraceEnabled()) {
log.trace("Creating session for host {}", s.getHost());
}
//保存session到SessionDAO
create(s);
return s;
}
//调用SessionFactory创建session
protected Session newSessionInstance(SessionContext context) {
return getSessionFactory().createSession(context);
}
//保存session到SessionDAO
protected void create(Session session) {
if (log.isDebugEnabled()) {
log.debug("Creating new EIS record for new session instance [" + session + "]");
}
sessionDAO.create(session);
}
@Override
protected void onStop(Session session) {
if (session instanceof SimpleSession) {
SimpleSession ss = (SimpleSession) session;
Date stopTs = ss.getStopTimestamp();
ss.setLastAccessTime(stopTs);
}
onChange(session);
}
@Override
protected void afterStopped(Session session) {
if (isDeleteInvalidSessions()) {
delete(session);
}
}
protected void onExpiration(Session session) {
if (session instanceof SimpleSession) {
((SimpleSession) session).setExpired(true);
}
onChange(session);
}
@Override
protected void afterExpired(Session session) {
if (isDeleteInvalidSessions()) {
delete(session);
}
}
protected void onChange(Session session) {
sessionDAO.update(session);
}
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
Serializable sessionId = getSessionId(sessionKey);
if (sessionId == null) {
log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " +
"session could not be found.", sessionKey);
return null;
}
//根据sessionID从SessionDAO中获取相对应的Session
Session s = retrieveSessionFromDataSource(sessionId);
if (s == null) {
//session ID was provided, meaning one is expected to be found, but we couldn't find one:
String msg = "Could not find session with ID [" + sessionId + "]";
throw new UnknownSessionException(msg);
}
return s;
}
//获取sessionKey里的SessionID
protected Serializable getSessionId(SessionKey sessionKey) {
return sessionKey.getSessionId();
}
//根据sessionID从SessionDAO中获取相对应的Session
protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException {
return sessionDAO.readSession(sessionId);
}
//删除session
protected void delete(Session session) {
sessionDAO.delete(session);
}
//获取SessionDAO的存在session
protected Collection getActiveSessions() {
Collection active = sessionDAO.getActiveSessions();
return active != null ? active : Collections.emptySet();
}
}
6.DefaultWebSessionManager
//基于WEB的SessionManager的实现
public class DefaultWebSessionManager extends DefaultSessionManager implements WebSessionManager {
private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
//Cookie基本模板
private Cookie sessionIdCookie;
//是否存储sessionID到cookie中,默认没有设置存活时间,即保存在浏览器开辟的内存中,没有持久化在硬盘上
private boolean sessionIdCookieEnabled;
public DefaultWebSessionManager() {
Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
//HttpOnly是防止用户通过js脚本获取cookie
cookie.setHttpOnly(true); //more secure, protects against XSS attacks
this.sessionIdCookie = cookie;
//默认允许存储sessionID到cookie中
this.sessionIdCookieEnabled = true;
}
//获取模板cookie
public Cookie getSessionIdCookie() {
return sessionIdCookie;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setSessionIdCookie(Cookie sessionIdCookie) {
this.sessionIdCookie = sessionIdCookie;
}
public boolean isSessionIdCookieEnabled() {
return sessionIdCookieEnabled;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
this.sessionIdCookieEnabled = sessionIdCookieEnabled;
}
//存储sessionID到cookie中
private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
if (currentId == null) {
String msg = "sessionId cannot be null when persisting for subsequent requests.";
throw new IllegalArgumentException(msg);
}
Cookie template = getSessionIdCookie();
Cookie cookie = new SimpleCookie(template);
String idString = currentId.toString();
cookie.setValue(idString);
cookie.saveTo(request, response);
log.trace("Set session ID cookie for session with id {}", idString);
}
//删除浏览器SessionID cookie
private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
getSessionIdCookie().removeFrom(request, response);
}
//根据sessionID Cookie获取sessionid
private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
if (!isSessionIdCookieEnabled()) {
log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
return null;
}
if (!(request instanceof HttpServletRequest)) {
log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie. Returning null.");
return null;
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
//从Cookie中读取sessionID
return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
}
//该方法尝试通过多种办法获取SessionID
private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
//首先在cookie中获取sessionID
String id = getSessionIdCookieValue(request, response);
if (id != null) {
//设置获取SessionID的来源 Cookie
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
} else {
//cookie不存在,尝试通过uri中获取
id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
if (id == null) {
//尝试中request的参数中获取
String name = getSessionIdName();
id = request.getParameter(name);
if (id == null) {
id = request.getParameter(name.toLowerCase());
}
}
if (id != null) {
//设置获取SessionID的来源 URL
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
}
}
if (id != null) {
//设置SessionUD
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
//设置SessionID有效.
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}
return id;
}
//通过URI获取SessionID
private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {
if (!(servletRequest instanceof HttpServletRequest)) {
return null;
}
HttpServletRequest request = (HttpServletRequest)servletRequest;
String uri = request.getRequestURI();
if (uri == null) {
return null;
}
int queryStartIndex = uri.indexOf('?');
if (queryStartIndex >= 0) { //get rid of the query string
uri = uri.substring(0, queryStartIndex);
}
int index = uri.indexOf(';'); //now check for path segment parameters:
if (index < 0) {
//no path segment params - return:
return null;
}
//there are path segment params, let's get the last one that may exist:
final String TOKEN = paramName + "=";
uri = uri.substring(index+1); //uri now contains only the path segment params
//we only care about the last JSESSIONID param:
index = uri.lastIndexOf(TOKEN);
if (index < 0) {
//no segment param:
return null;
}
uri = uri.substring(index + TOKEN.length());
index = uri.indexOf(';'); //strip off any remaining segment params:
if(index >= 0) {
uri = uri.substring(0, index);
}
return uri; //what remains is the value
}
//获取sessionid存储的名字
private String getSessionIdName() {
String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
if (name == null) {
name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
}
return name;
}
//封装一个基于WEB(包含request和response的支持)的 客户端层session,该方法主要用在新创建session
protected Session createExposedSession(Session session, SessionContext context) {
if (!WebUtils.isWeb(context)) {
return super.createExposedSession(session, context);
}
ServletRequest request = WebUtils.getRequest(context);
ServletResponse response = WebUtils.getResponse(context);
SessionKey key = new WebSessionKey(session.getId(), request, response);
return new DelegatingSession(this, key);
}
//封装一个基于WEB(包含request和response的支持)的 客户端层session,该方法主要用在获取已存在的session
protected Session createExposedSession(Session session, SessionKey key) {
if (!WebUtils.isWeb(key)) {
return super.createExposedSession(session, key);
}
ServletRequest request = WebUtils.getRequest(key);
ServletResponse response = WebUtils.getResponse(key);
SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
return new DelegatingSession(this, sessionKey);
}
//session start创建后保存sessionID到客户端浏览器cookie中
@Override
protected void onStart(Session session, SessionContext context) {
super.onStart(session, context);
if (!WebUtils.isHttp(context)) {
log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +
"pair. No session ID cookie will be set.");
return;
}
HttpServletRequest request = WebUtils.getHttpRequest(context);
HttpServletResponse response = WebUtils.getHttpResponse(context);
//判断是否允许存储sessionID到cookie中
if (isSessionIdCookieEnabled()) {
Serializable sessionId = session.getId();
storeSessionId(sessionId, request, response);
} else {
log.debug("Session ID cookie is disabled. No cookie has been set for new session with id {}", session.getId());
}
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
//设置session为新创建
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
}
//获取sessionID
@Override
public Serializable getSessionId(SessionKey key) {
Serializable id = super.getSessionId(key);
if (id == null && WebUtils.isWeb(key)) {
//WebSessionKey中封装着request和response
ServletRequest request = WebUtils.getRequest(key);
ServletResponse response = WebUtils.getResponse(key);
id = getSessionId(request, response);
}
return id;
}
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
return getReferencedSessionId(request, response);
}
@Override
protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
super.onExpiration(s, ese, key);
onInvalidation(key);
}
@Override
protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
super.onInvalidation(session, ise, key);
onInvalidation(key);
}
//无效session后续操作
private void onInvalidation(SessionKey key) {
ServletRequest request = WebUtils.getRequest(key);
if (request != null) {
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
}
if (WebUtils.isHttp(key)) {
log.debug("Referenced session was invalid. Removing session ID cookie.");
removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
} else {
log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
"pair. Session ID cookie will not be removed due to invalidated session.");
}
}
@Override
protected void onStop(Session session, SessionKey key) {
super.onStop(session, key);
if (WebUtils.isHttp(key)) {
HttpServletRequest request = WebUtils.getHttpRequest(key);
HttpServletResponse response = WebUtils.getHttpResponse(key);
//删除sessionID cookie
removeSessionIdCookie(request, response);
} else {
log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
"pair. Session ID cookie will not be removed due to stopped session.");
}
}
//用于判断是否使用serlvet的session
public boolean isServletContainerSessions() {
return false;
}
}