• tomcat对sessionId的处理分析


    tomcat 7对sessionId的处理:

    首先解析request请求中的sessionID:

    从AjpProcessor.java的process(SocketWrapper<Socket> socket)调用CoyoteAdapter.process里面有的postParseRequest(org.apache.coyote.Request req, Request request,org.apache.coyote.Response res,

      Response response) 就有解析获取sessionid的过程

      // Now we have the context, we can parse the session ID from the URL
                // (if any). Need to do this before we redirect in case we need to
                // include the session id in the redirect
                String sessionID = null;
                if (request.getServletContext().getEffectiveSessionTrackingModes()
                        .contains(SessionTrackingMode.URL)) {
    
                    // Get the session ID if there was one
                    sessionID = request.getPathParameter(
                            SessionConfig.getSessionUriParamName(
                                    request.getContext()));
                    if (sessionID != null) {
                        request.setRequestedSessionId(sessionID);
                        request.setRequestedSessionURL(true);
                    }
                }
    
                // Look for session ID in cookies and SSL session
                parseSessionCookiesId(req, request);
                parseSessionSslId(request);
    
     /**
         * Look for SSL session ID if required. Only look for SSL Session ID if it
         * is the only tracking method enabled.
         */
        protected void parseSessionSslId(Request request) {
            if (request.getRequestedSessionId() == null &&
                    SSL_ONLY.equals(request.getServletContext()
                            .getEffectiveSessionTrackingModes()) &&
                            request.connector.secure) {
                // TODO Is there a better way to map SSL sessions to our sesison ID?
                // TODO The request.getAttribute() will cause a number of other SSL
                //      attribute to be populated. Is this a performance concern?
                request.setRequestedSessionId(
                        request.getAttribute(SSLSupport.SESSION_ID_KEY).toString());
                request.setRequestedSessionSSL(true);
            }
        }
    
    
        /**
         * Parse session id in URL.
         */
        protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {
    
            // If session tracking via cookies has been disabled for the current
            // context, don't go looking for a session ID in a cookie as a cookie
            // from a parent context with a session ID may be present which would
            // overwrite the valid session ID encoded in the URL
            Context context = (Context) request.getMappingData().context;
            if (context != null && !context.getServletContext()
                    .getEffectiveSessionTrackingModes().contains(
                            SessionTrackingMode.COOKIE)) {
                return;
            }
    
            // Parse session id from cookies
            Cookies serverCookies = req.getCookies();
            int count = serverCookies.getCookieCount();
            if (count <= 0) {
                return;
            }
    
            String sessionCookieName = SessionConfig.getSessionCookieName(context);
    
            for (int i = 0; i < count; i++) {
                ServerCookie scookie = serverCookies.getCookie(i);
                if (scookie.getName().equals(sessionCookieName)) {
                    // Override anything requested in the URL
                    if (!request.isRequestedSessionIdFromCookie()) {
                        // Accept only the first session id cookie
                        convertMB(scookie.getValue());
                        request.setRequestedSessionId
                            (scookie.getValue().toString());
                        request.setRequestedSessionCookie(true);
                        request.setRequestedSessionURL(false);
                        if (log.isDebugEnabled()) {
                            log.debug(" Requested cookie session id is " +
                                request.getRequestedSessionId());
                        }
                    } else {
                        if (!request.isRequestedSessionIdValid()) {
                            // Replace the session id until one is valid
                            convertMB(scookie.getValue());
                            request.setRequestedSessionId
                                (scookie.getValue().toString());
                        }
                    }
                }
            }
    
        }

    如果没有sessionId,则在request.getSession()的时候需要进行处理

    public class Request
        implements HttpServletRequest {
    
    ......
        /**
         * Return the session associated with this Request, creating one
         * if necessary.
         */
        @Override
        public HttpSession getSession() {
            Session session = doGetSession(true);
            if (session == null) {
                return null;
            }
    
            return session.getSession();
        }
    
    
        /**
         * Return the session associated with this Request, creating one
         * if necessary and requested.
         *
         * @param create Create a new session if one does not exist
         */
        @Override
        public HttpSession getSession(boolean create) {
            Session session = doGetSession(create);
            if (session == null) {
                return null;
            }
    
            return session.getSession();
        }
    
      // ------------------------------------------------------ Protected Methods
    
    
        protected Session doGetSession(boolean create) {
    
            // There cannot be a session if no context has been assigned yet
            if (context == null) {
                return (null);
            }
    
            // Return the current session if it exists and is valid
            if ((session != null) && !session.isValid()) {
                session = null;
            }
            if (session != null) {
                return (session);
            }
    
            // Return the requested session if it exists and is valid
            Manager manager = null;
            if (context != null) {
                manager = context.getManager();
            }
            if (manager == null)
             {
                return (null);      // Sessions are not supported
            }
            if (requestedSessionId != null) {
                try {
                    session = manager.findSession(requestedSessionId);
                } catch (IOException e) {
                    session = null;
                }
                if ((session != null) && !session.isValid()) {
                    session = null;
                }
                if (session != null) {
                    session.access();
                    return (session);
                }
            }
    
            // Create a new session if requested and the response is not committed
            if (!create) {
                return (null);
            }
            if ((context != null) && (response != null) &&
                context.getServletContext().getEffectiveSessionTrackingModes().
                        contains(SessionTrackingMode.COOKIE) &&
                response.getResponse().isCommitted()) {
                throw new IllegalStateException
                  (sm.getString("coyoteRequest.sessionCreateCommitted"));
            }
    
            // Attempt to reuse session id if one was submitted in a cookie
            // Do not reuse the session id if it is from a URL, to prevent possible
            // phishing attacks
            // Use the SSL session ID if one is present.
            if (("/".equals(context.getSessionCookiePath())
                    && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {
                session = manager.createSession(getRequestedSessionId());
            } else {
                session = manager.createSession(null);
            }
    
            // Creating a new session cookie based on that session
            if ((session != null) && (getContext() != null)
                   && getContext().getServletContext().
                           getEffectiveSessionTrackingModes().contains(
                                   SessionTrackingMode.COOKIE)) {
                Cookie cookie =
                    ApplicationSessionCookieConfig.createSessionCookie(
                            context, session.getIdInternal(), isSecure());
    
                response.addSessionCookieInternal(cookie);
            }
    
            if (session == null) {
                return null;
            }
    
            session.access();
            return session;
        }
     ......
    ......

    上面会通过manager.createSession创建session,如果request请求带了sessionId,则传入该参数

    ,没有的话则会创建一个,并且会把sessionId放入response的cookie中

    manager对应ManagerBase.java类,里面生成session的过程如下:


        /**
         * Construct and return a new session object, based on the default
         * settings specified by this Manager's properties.  The session
         * id specified will be used as the session id.  
         * If a new session cannot be created for any reason, return 
         * <code>null</code>.
         * 
         * @param sessionId The session id which should be used to create the
         *  new session; if <code>null</code>, a new session id will be
         *  generated
         * @exception IllegalStateException if a new session cannot be
         *  instantiated for any reason
         */
        @Override
        public Session createSession(String sessionId) {
            
            if ((maxActiveSessions >= 0) &&
                    (getActiveSessions() >= maxActiveSessions)) {
                rejectedSessions++;
                throw new IllegalStateException(
                        sm.getString("managerBase.createSession.ise"));
            }
            
            // Recycle or create a Session instance
            Session session = createEmptySession();
    
            // Initialize the properties of the new session and return it
            session.setNew(true);
            session.setValid(true);
            session.setCreationTime(System.currentTimeMillis());
            session.setMaxInactiveInterval(this.maxInactiveInterval);
            String id = sessionId;
            if (id == null) {
                id = generateSessionId();
            }
            session.setId(id);
            sessionCounter++;
    
            SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
            synchronized (sessionCreationTiming) {
                sessionCreationTiming.add(timing);
                sessionCreationTiming.poll();
            }
            return (session);
    
        }
        /**
         * Generate and return a new session identifier.
         */
        protected String generateSessionId() {
    
            String result = null;
    
            do {
                if (result != null) {
                    // Not thread-safe but if one of multiple increments is lost
                    // that is not a big deal since the fact that there was any
                    // duplicate is a much bigger issue.
                    duplicates++;
                }
    
                result = sessionIdGenerator.generateSessionId();
                
            } while (sessions.containsKey(result));
            
            return result;
        }
    ......

    sesseionIdGenerator生成sessionId的算法如下:


      /**
         * Generate and return a new session identifier.
         */
        public String generateSessionId() {
    
            byte random[] = new byte[16];
    
            // Render the result as a String of hexadecimal digits
            StringBuilder buffer = new StringBuilder();
    
            int resultLenBytes = 0;
    
            while (resultLenBytes < sessionIdLength) {
                getRandomBytes(random);
                for (int j = 0;
                j < random.length && resultLenBytes < sessionIdLength;
                j++) {
                    byte b1 = (byte) ((random[j] & 0xf0) >> 4);
                    byte b2 = (byte) (random[j] & 0x0f);
                    if (b1 < 10)
                        buffer.append((char) ('0' + b1));
                    else
                        buffer.append((char) ('A' + (b1 - 10)));
                    if (b2 < 10)
                        buffer.append((char) ('0' + b2));
                    else
                        buffer.append((char) ('A' + (b2 - 10)));
                    resultLenBytes++;
                }
            }
    
            if (jvmRoute != null && jvmRoute.length() > 0) {
                buffer.append('.').append(jvmRoute);
            }
    
            return buffer.toString();
        }

    其中jvmRoute是为了防止tomcat集群导致的sessionId冲突,getRandomBytes(random);会通过随机算法生成16byte的字节数组,最终sessionId默认是生成16byte的字符串。

     

    上面说到会把生成的sessionId存入response的cookie域中


    Cookie cookie =
                    ApplicationSessionCookieConfig.createSessionCookie(
                            context, session.getIdInternal(), isSecure());
    
                response.addSessionCookieInternal(cookie);

    处理过程如下:

      /**
         * Special method for adding a session cookie as we should be overriding
         * any previous
         * @param cookie
         */
        public void addSessionCookieInternal(final Cookie cookie) {
            if (isCommitted()) {
                return;
            }
    
            String name = cookie.getName();
            final String headername = "Set-Cookie";
            final String startsWith = name + "=";
            final StringBuffer sb = generateCookieString(cookie);
            boolean set = false;
            MimeHeaders headers = coyoteResponse.getMimeHeaders();
            int n = headers.size();
            for (int i = 0; i < n; i++) {
                if (headers.getName(i).toString().equals(headername)) {
                    if (headers.getValue(i).toString().startsWith(startsWith)) {
                        headers.getValue(i).setString(sb.toString());
                        set = true;
                    }
                }
            }
            if (!set) {
                addHeader(headername, sb.toString());
            }
    
    
        }
    

    如果header已经有这个sessionId的cookie,则更新,否则设置到header中。

  • 相关阅读:
    CF1435E Solo mid Oracle(推柿子)
    CF1435C Perform Easily(Set)
    NC7501I (反向建图)
    NC7501D Router Mesh (去掉割点算连通快的变化)
    超全的Python第三方库
    字符串常见题目
    IDEA的常用设置大全
    IDEA的介绍与安装
    涨姿势啦(1)
    Torch常用的函数总结
  • 原文地址:https://www.cnblogs.com/secbook/p/2655155.html
Copyright © 2020-2023  润新知