shiro 獲取請求頭中的 sessionId

前言:

  在先後端項目中, 前端有可能會要求, 後臺返回一個 sessionId 給他, 而後他在請求後臺接口時, 把這個sessionId 帶給後臺, 後臺拿到這個sessionId , 就能識別, 是那個用戶. 前端

  在shiro中, 會返回一個 JSESSIONID , 其實就是sessionId .java

  若是不想把sessionId 放在參數中, 或者貼在連接後面, 暴露給用戶, 那麼咱們還能選擇把 sessionId 放在請求頭中, 這樣比較隱祕一些. 不會那麼明顯.web

一.  DefaultWebSessionManager

  在配置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

  

二. 自定義 DefaultWebSessionManager 類

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放入到請求頭中, 在訪問接口

確實能夠識別用戶, 拿到數據.

相關文章
相關標籤/搜索