`

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中。

 

 

 

16
55
分享到:
评论
2 楼 featuretower 2013-03-08  
public class Request 
    implements HttpServletRequest { 
Request是什么类来的,在doGetSession里context是它的私有变量? context是什么类型呢,什么时候初始化??
1 楼 z276356445t 2012-07-30  
tomcat不是一直都将JSESSIONID放入cookie中的?

相关推荐

    tomcat-redis-session-manager-master.zip

    通过上述分析,我们可以看到,Tomcat Redis Session Manager提供了便捷的session共享机制,有效地解决了高并发场景下的session管理问题。通过对源码的学习和实践,开发者可以更好地理解和掌握这一技术,提升系统的可...

    tomcat session共享负载

    本文将深入探讨如何在Tomcat中实现Session的共享,并分析其背后的原理和配置方法。 首先,我们要理解Session的基本概念。Session是Web服务器为用户创建的一段持久性存储空间,用于存储用户在访问网站期间产生的状态...

    tomcat-redis-session-manager源码

    `RedisSession`是`RedisSessionManager`内部用于表示会话的对象,它继承自`org.apache.catalina.Session`,并扩展了对Redis特性的支持,如序列化和反序列化。会话数据在Redis中以哈希(Hash)形式存储,便于高效地...

    Tomcat中实现Session小结

    总结来说,Tomcat中的Session是通过Session ID(JSESSIONID)作为标识,结合Cookie在客户端和服务器之间传递,实现对用户会话状态的跟踪。了解这些原理对于优化Web应用性能、处理会话管理问题以及确保用户安全性至关...

    tomcat6源码分析

    总结,Tomcat6源码分析是深入了解Web服务器运行机制的重要途径,通过对源码的学习,我们可以掌握其内部的工作原理,从而在实际开发中实现更高效、更稳定的应用部署和维护。这是一份宝贵的资源,值得我们深入研究和...

    深入浅析TomCat Session管理分析

    【深入浅析TomCat Session管理分析】 Session在Java Web开发中扮演着至关重要的角色,它允许服务器跟踪用户的交互,存储用户的状态信息。Tomcat作为广泛使用的开源Servlet容器,其内部的Session管理机制对于理解Web...

    浅谈Tomcat Session管理分析

    1. 创建:当用户首次访问应用并请求Session时,Tomcat会通过`SessionIdGenerator`生成一个唯一的Session ID,然后创建一个新的Session对象。 2. 获取:通过`request.getSession()`方法,Tomcat检查请求头中的...

    Nginx.tomcat.memcached负载均衡和session共享.rar

    在IT行业中,构建高效、可扩展的Web应用架构是至关重要的。本压缩包"**Nginx.tomcat....通过对Nginx、Tomcat、Memcached的合理利用和集成,我们可以构建出一个稳定、可扩展且能有效处理Session共享问题的Web服务系统。

    tomcat8源码

    Tomcat提供会话跟踪,通过Session ID来识别用户会话。会话管理包括创建、更新、过期和移除会话。默认使用Cookie进行会话追踪,但也可以配置为URL重写或基于SSL的会话追踪。 7. **安全性** Tomcat通过JaasRealm和...

    tomcat 7.0.42 聊天一对一,多对多实现

    每个用户登录时,会生成一个唯一的Session ID,用于标识该用户,然后通过这个ID来区分不同的聊天会话。 多对多聊天则相对复杂一些,它涉及到多个用户之间的消息广播。为了实现这一点,可能需要一个公共的消息队列...

    tomcat7 源码

    Session ID存储在cookie中,服务器通过Session Manager和Session ID跟踪用户会话。 6. **安全性** Tomcat支持多种安全策略,如SSL/TLS加密, Realm(认证域)进行用户身份验证,以及角色授权。可以通过` Realm `...

    tomcat源码,servlet-api源码

    当客户端请求携带会话ID时,Tomcat根据ID查找并恢复会话状态。此外,Tomcat还支持会话超时、分布式会话和会话持久化等高级功能。 5. **安全性与权限控制** Tomcat使用Realm组件进行身份验证,如MemoryRealm、...

    Session

    每当用户发送请求时,浏览器会通过Cookie将这个Session ID返回给服务器,服务器根据ID找到对应的Session数据,实现对用户状态的跟踪。 Session的实现通常涉及到以下步骤: 1. 用户首次访问网站时,服务器生成一个...

    WEB服务器工作机制由浅至深(3):【How Tomcat Works】5~6章翻译分析

    Session是服务器端保持用户状态的一种方式,当客户端发送请求时,Tomcat会检查Cookie中的Session ID,如果存在,就从内存或持久化存储中恢复相关的Session数据。此外,Tomcat提供了会话跟踪模块,如URL重写、隐藏...

    java session

    通过合理的配置和对对象的序列化处理,可以有效避免因Session管理不当而导致的异常,提高系统的稳定性和用户体验。 通过本篇文章的学习,我们可以更好地理解和掌握Java Session的相关知识点,为日常的Web开发工作...

    tomcat-source:tomcat源码分析

    通过对Tomcat源码的深入学习,我们可以更好地理解其内部工作原理,从而更好地优化应用性能,解决运行时问题,甚至为Tomcat开发新的功能或模块。这个过程不仅提升了编程技能,也为参与其他Java Web项目的开发打下了...

    tomcat8.0源码

    Tomcat支持会话跟踪,使用session ID来识别用户会话。源码揭示了会话创建、过期、复制和分布式管理的实现。 7. **JSP编译**: Jasper组件负责JSP文件的编译成Servlet。通过源码,开发者可以理解JSP到Servlet的...

    javaee-Session持久化小结

    例如,可以使用Servlet容器(如Tomcat)的内置Session持久化配置,或者自定义实现`HttpSessionListener`和`HttpSessionBindingListener`来监听Session的创建和销毁事件,进行手动持久化操作。 标签中的"源码"可能...

    Nignx 连接tomcat时会话粘性问题分析及解决方法

    在分布式系统中,特别是使用 Nginx 作为反向代理服务器与多台 Tomcat 应用服务器集群配合时,会话粘性(Session Stickiness)是一个重要的考虑因素。会话粘性是指确保来自同一用户的请求被转发到同一台后端服务器,...

Global site tag (gtag.js) - Google Analytics