
SessionManager接口就两个方法,Session start(SessionContext context)和Session getSession(SessionKey key) throws SessionException
其中start方法,将会在创建session时调用,即getSession(true)时调用。
下面代码是DelegatingSubject.getSession方法
public Session getSession(boolean create) {
if (log.isTraceEnabled()) {
log.trace("attempting to get session; create = " + create +
"; session is null = " + (this.session == null) +
"; session has id = " + (this.session != null && session.getId() != null));
}
if (this.session == null && create) {
//added in 1.2:
if (!isSessionCreationEnabled()) {
String msg = "Session creation has been disabled for the current subject. This exception indicates " +
"that there is either a programming error (using a session when it should never be " +
"used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " +
"for the current Subject. See the " + DisabledSessionException.class.getName() + " JavaDoc " +
"for more.";
throw new DisabledSessionException(msg);
}
log.trace("Starting session for host {}", getHost());
SessionContext sessionContext = createSessionContext();
Session session = this.securityManager.start(sessionContext);
this.session = decorate(session);
}
return this.session;
}getSession(sessionKey) 根据sessionKey获取session,它会调用lookupSession(key),然后调用doGetSession(key)。
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);
}doGetSession(sessionKey)会调用retrieveSession方法。
protected final Session doGetSession(final SessionKey key) throws InvalidSessionException {
enableSessionValidationIfNecessary();
log.trace("Attempting to retrieve session with key {}", key);
Session s = retrieveSession(key);
if (s != null) {
validate(s, key);
}
return s;
}retrieveSession(sessionKey)会调用getSessionId(sessionKey),
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;
}
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;
}getSessionId是最重要的方法,我们要实现一个基于Token的SessionManager,我们可以继承DefaultWebSessionManager,它默认是可以基于Cookie与Url来获得sessionId,所以我们只要实现getSessionId(ServletRequest request, ServletResponse reponse)和onStart(Session session, SessionContext context)方法即可。
@Override
protected void onStart(Session session, SessionContext context)
{
super.onStart(session, context);
if (WebUtils.isHttp(context))
{
HttpServletRequest request = WebUtils.getHttpRequest(context);
Serializable sessionId = session.getId();
request.setAttribute(AUTH_TOKEN, sessionId);
}
}这里仅需在reqeust设置属性即可,记录的是sessionId。调用这个方法还会继续调用getSessionId,所以设置SessionId的操作放到那个方法去执行:
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response)
{
if (!(request instanceof HttpServletRequest))
{
logger.debug("Current request is not an HttpServletRequest - cannot get session ID. Returning null.");
return null;
}
HttpServletRequest httpRequest = WebUtils.toHttp(request);
if (StringUtils.hasText(httpRequest.getHeader(AUTH_TOKEN)))
{
//从header中获取token
String token = httpRequest.getHeader(AUTH_TOKEN);
// 每次读取之后都把当前的token放入response中
HttpServletResponse httpResponse = WebUtils.toHttp(response);
if (StringUtils.hasText(token))
{
httpResponse.setHeader(AUTH_TOKEN, token);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "header");
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}
//sessionIdUrlRewritingEnabled的配置为false,不会在url的后面带上sessionID
request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, false);
return token;
}
else
{
return super.getSessionId(request, response);
}
}将SessionId放到response的header中,每次请求在request的header中设置token,将回去底层的session中查找。