在先後端項目中, 前端有可能會要求, 後臺返回一個 sessionId 給他, 而後他在請求後臺接口時, 把這個sessionId 帶給後臺, 後臺拿到這個sessionId , 就能識別, 是那個用戶. 前端
在shiro中, 會返回一個 JSESSIONID , 其實就是sessionId .java
若是不想把sessionId 放在參數中, 或者貼在連接後面, 暴露給用戶, 那麼咱們還能選擇把 sessionId 放在請求頭中, 這樣比較隱祕一些. 不會那麼明顯.web
在配置shiro的時候, 咱們常常會配置 org.apache.shiro.web.session.mgt.DefaultWebSessionManager , 那麼咱們先來看看這個類中的相關方法吧.apache
1. onStart 方法後端
在這個方法中, 咱們其實能夠很明顯的看到有一個storeSessionId 方法, 在這個方法中, 會將 sessionId 存入到cookie中.瀏覽器
若是咱們能夠繼承這個類, 而後重寫onStart方法, 那麼是否能夠實現, 將sessionId放到響應頭中去, 前端能夠從響應頭中獲取到sessionId.cookie
那既然有處理sesisonId的方法, 那麼是否有get sessionId的方法呢? 若是有這個方法, 咱們重寫它, 改成從請求頭中讀取sessionid, 不就能夠了麼.session
那來找一下看看:ide
確實有的. 裏面的具體實現, 就不看了, 不是這篇的主題.post
import org.apache.commons.lang.StringUtils; import org.apache.shiro.session.ExpiredSessionException; import org.apache.shiro.session.InvalidSessionException; import org.apache.shiro.session.Session; import org.apache.shiro.session.mgt.DefaultSessionManager; import org.apache.shiro.session.mgt.DelegatingSession; import org.apache.shiro.session.mgt.SessionContext; import org.apache.shiro.session.mgt.SessionKey; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.WebSessionKey; import org.apache.shiro.web.session.mgt.WebSessionManager; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.Serializable; public class DefaultHeaderSessionManager extends DefaultSessionManager implements WebSessionManager { private static final Logger log = LoggerFactory.getLogger(DefaultHeaderSessionManager.class); private final String X_AUTH_TOKEN = "x-auth-token"; @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."); } else { HttpServletRequest request = WebUtils.getHttpRequest(context); HttpServletResponse response = WebUtils.getHttpResponse(context); Serializable sessionId = session.getId(); this.storeSessionId(sessionId, request, response); request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE); 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)) { ServletRequest request = WebUtils.getRequest(key); ServletResponse response = WebUtils.getResponse(key); id = getSessionId(request, response); } return id; } protected Serializable getSessionId(ServletRequest request, ServletResponse response) { return this.getReferencedSessionId(request, response); } // 請求頭中獲取 sessionId 並把sessionId 放入 response 中 private String getSessionIdHeaderValue(ServletRequest request, ServletResponse response) { if (!(request instanceof HttpServletRequest)) { log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie. Returning null."); return null; } else { HttpServletRequest httpRequest = (HttpServletRequest) request; // 在request 中 讀取 x-auth-token 信息 做爲 sessionId String sessionId = httpRequest.getHeader(this.X_AUTH_TOKEN); // 每次讀取以後 都把當前的 sessionId 放入 response 中 HttpServletResponse httpResponse = (HttpServletResponse) response; if (StringUtils.isNotEmpty(sessionId)) { httpResponse.setHeader(this.X_AUTH_TOKEN, sessionId); log.info("Current session ID is {}", sessionId); } return sessionId; } } //獲取sessionid private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) { String id = this.getSessionIdHeaderValue(request, response); //DefaultWebSessionManager 中代碼 直接copy過來 if (id != null) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "header"); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); } //不會把sessionid放在URL後 request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.FALSE); return id; } // 移除sessionid 並設置爲 deleteMe 標識 private void removeSessionIdHeader(HttpServletRequest request, HttpServletResponse response) { response.setHeader(this.X_AUTH_TOKEN, "deleteMe"); } /** * 把sessionId 放入 response header 中 * onStart時調用 * 沒有sessionid時 會產生sessionid 並放入 response header中 */ private void storeSessionId(Serializable currentId, HttpServletRequest ignored, HttpServletResponse response) { if (currentId == null) { String msg = "sessionId cannot be null when persisting for subsequent requests."; throw new IllegalArgumentException(msg); } else { String idString = currentId.toString(); response.setHeader(this.X_AUTH_TOKEN, idString); log.info("Set session ID header for session with id {}", idString); log.trace("Set session ID header for session with id {}", idString); } } // 建立session @Override protected Session createExposedSession(Session session, SessionContext context) { if (!WebUtils.isWeb(context)) { return super.createExposedSession(session, context); } else { ServletRequest request = WebUtils.getRequest(context); ServletResponse response = WebUtils.getResponse(context); SessionKey key = new WebSessionKey(session.getId(), request, response); return new DelegatingSession(this, key); } } @Override protected Session createExposedSession(Session session, SessionKey key) { if (!WebUtils.isWeb(key)) { return super.createExposedSession(session, key); } else { ServletRequest request = WebUtils.getRequest(key); ServletResponse response = WebUtils.getResponse(key); SessionKey sessionKey = new WebSessionKey(session.getId(), request, response); return new DelegatingSession(this, sessionKey); } } @Override protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) { super.onExpiration(s, ese, key); this.onInvalidation(key); } @Override protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) { super.onInvalidation(session, ise, key); this.onInvalidation(key); } 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 header."); this.removeSessionIdHeader(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); log.debug("Session has been stopped (subject logout or explicit stop). Removing session ID cookie."); this.removeSessionIdHeader(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."); } } @Override public boolean isServletContainerSessions() { return false; } }
<bean id="sessionManager" class="ccdc.zykt.web.shiro.headtoken.DefaultHeaderSessionManager"> <property name="sessionDAO" ref="sessionDAO"/> <property name="globalSessionTimeout" value="3600000"/> <property name="sessionValidationInterval" value="3600000"/> </bean> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>
1. 經過瀏覽器訪問登陸接口, 拿到sessionId, 也就是這裏的 x-auth-token
2. 打開postman, 將x-auth-token放入到請求頭中, 在訪問接口
確實能夠識別用戶, 拿到數據.