zoukankan      html  css  js  c++  java
  • shiro 获取请求头中的 sessionId

    前言:

      在前后端项目中, 前端有可能会要求, 后台返回一个 sessionId 给他, 然后他在请求后台接口时, 把这个sessionId 带给后台, 后台拿到这个sessionId , 就能识别, 是那个用户. 

      在shiro中, 会返回一个 JSESSIONID , 其实就是sessionId .

      如果不想把sessionId 放在参数中, 或者贴在链接后面, 暴露给用户, 那么我们还能选择把 sessionId 放在请求头中, 这样比较隐秘一些. 不会那么明显.

    一.  DefaultWebSessionManager

      在配置shiro的时候, 我们经常会配置  org.apache.shiro.web.session.mgt.DefaultWebSessionManager , 那么我们先来看看这个类中的相关方法吧.

    1. onStart 方法

      

      在这个方法中, 我们其实可以很明显的看到有一个storeSessionId 方法, 在这个方法中, 会将 sessionId 存入到cookie中.

      

      如果我们可以继承这个类, 然后重写onStart方法, 那么是否可以实现, 将sessionId放到响应头中去, 前端可以从响应头中获取到sessionId.

        那既然有处理sesisonId的方法, 那么是否有get sessionId的方法呢? 如果有这个方法, 我们重写它, 改为从请求头中读取sessionid, 不就可以了么.

      那来找一下看看:

      

      确实有的. 里面的具体实现, 就不看了, 不是这篇的主题.

      

    二. 自定义 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放入到请求头中, 在访问接口

    确实可以识别用户, 拿到数据.

  • 相关阅读:
    阶段性总结(PHP-JSON)
    阶段性总结(PHP-Array函数)
    JavaScript异步加载的三种方式——async和defer、动态创建script
    event.target 和 event.currentTarget 的区别
    面试题:常用的http状态码
    JS变量重复声明以及忽略var 声明的问题及其背后的原理
    line-height:1.5和line-height:150%的区别
    Web前端性能优化——如何提高页面加载速度
    Promise和setTimeout执行顺序 面试题
    过目不忘JS正则表达式
  • 原文地址:https://www.cnblogs.com/elvinle/p/9272076.html
Copyright © 2011-2022 走看看