从tomcat 8源码观session cookie maxage的配置
从tomcat 8源码看session cookie maxage的配置
最近有兴趣看了tomcat 8源码对session cookie的处理,才发现web.xml支持对session cookie配置maxage,如果不配置默认就是-1,-1表示这个cookie在当前浏览器窗口有效,存放在内存中而不是硬盘,关掉当前浏览器窗口的话,这个cookie失效,会话结束;如果设置了maxage(不等于-1),则存放到硬盘。
部分源码:
org/apache/catalina/connector/Request.java
createSessionCookie:创建一个sessionCookie,并添加到response
protected Session doGetSession(boolean create) { ................. ................. ................. // Creating a new session cookie based on that session if (session != null && context.getServletContext() .getEffectiveSessionTrackingModes() .contains(SessionTrackingMode.COOKIE)) { Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie( context, session.getIdInternal(), isSecure()); response.addSessionCookieInternal(cookie); } ................. ................. ................. }
org/apache/catalina/core/ApplicationSessionCookieConfig.java
private int maxAge = -1; //默认等于-1
scc.getMaxAge():从scc里取得maxAge
package org.apache.catalina.core; import javax.servlet.SessionCookieConfig; import javax.servlet.http.Cookie; import org.apache.catalina.Context; import org.apache.catalina.LifecycleState; import org.apache.catalina.util.SessionConfig; import org.apache.tomcat.util.res.StringManager; public class ApplicationSessionCookieConfig implements SessionCookieConfig { /** * The string manager for this package. */ private static final StringManager sm = StringManager .getManager(Constants.Package); private boolean httpOnly; private boolean secure; private int maxAge = -1; private String comment; private String domain; private String name; private String path; private StandardContext context; ................. ................. ................. @Override public int getMaxAge() { return maxAge; } ................. ................. ................. /** * Creates a new session cookie for the given session ID * * @param context The Context for the web application * @param sessionId The ID of the session for which the cookie will be * created * @param secure Should session cookie be configured as secure * @return the cookie for the session */ public static Cookie createSessionCookie(Context context, String sessionId, boolean secure) { SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); // NOTE: The priority order for session cookie configuration is: // 1. Context level configuration // 2. Values from SessionCookieConfig // 3. Defaults Cookie cookie = new Cookie( SessionConfig.getSessionCookieName(context), sessionId); // Just apply the defaults. cookie.setMaxAge(scc.getMaxAge()); cookie.setComment(scc.getComment()); ................. ................. ................. } }
org/apache/catalina/startup/ContextConfig.java
scc.setMaxAge:读取web.xml里面session-config的max-age并set到scc
package org.apache.catalina.startup; ................. ................. ................. /** * Startup event listener for a <b>Context</b> that configures the properties * of that Context, and the associated defined servlets. * * @author Craig R. McClanahan */ public class ContextConfig implements LifecycleListener { ................. ................. ................. /** * Process a "contextConfig" event for this Context. */ protected synchronized void configureStart() { // Called from StandardContext.start() if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.start")); } if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.xmlSettings", context.getName(), Boolean.valueOf(context.getXmlValidation()), Boolean.valueOf(context.getXmlNamespaceAware()))); } webConfig(); ................. ................. ................. } ................. ................. ................. /** * Scan the web.xml files that apply to the web application and merge them * using the rules defined in the spec. For the global web.xml files, * where there is duplicate configuration, the most specific level wins. ie * an application's web.xml takes precedence over the host level or global * web.xml file. */ protected void webConfig() { /* * Anything and everything can override the global and host defaults. * This is implemented in two parts * - Handle as a web fragment that gets added after everything else so * everything else takes priority * - Mark Servlets as overridable so SCI configuration can replace * configuration from the defaults */ /* * The rules for annotation scanning are not as clear-cut as one might * think. Tomcat implements the following process: * - As per SRV.1.6.2, Tomcat will scan for annotations regardless of * which Servlet spec version is declared in web.xml. The EG has * confirmed this is the expected behaviour. * - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main * web.xml is marked as metadata-complete, JARs are still processed * for SCIs. * - If metadata-complete=true and an absolute ordering is specified, * JARs excluded from the ordering are also excluded from the SCI * processing. * - If an SCI has a @HandlesType annotation then all classes (except * those in JARs excluded from an absolute ordering) need to be * scanned to check if they match. */ WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(), context.getXmlValidation(), context.getXmlBlockExternal()); Set<WebXml> defaults = new HashSet<>(); defaults.add(getDefaultWebXmlFragment(webXmlParser)); WebXml webXml = createWebXml(); // Parse context level web.xml InputSource contextWebXml = getContextWebXmlSource(); if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) { ok = false; } ................. ................. ................. configureContext(webXml); ................. ................. ................. } private void configureContext(WebXml webxml) { ................. ................. ................. SessionConfig sessionConfig = webxml.getSessionConfig(); if (sessionConfig != null) { if (sessionConfig.getSessionTimeout() != null) { context.setSessionTimeout( sessionConfig.getSessionTimeout().intValue()); } SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); scc.setName(sessionConfig.getCookieName()); scc.setDomain(sessionConfig.getCookieDomain()); scc.setPath(sessionConfig.getCookiePath()); scc.setComment(sessionConfig.getCookieComment()); if (sessionConfig.getCookieHttpOnly() != null) { scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue()); } if (sessionConfig.getCookieSecure() != null) { scc.setSecure(sessionConfig.getCookieSecure().booleanValue()); } if (sessionConfig.getCookieMaxAge() != null) { scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue()); } if (sessionConfig.getSessionTrackingModes().size() > 0) { context.getServletContext().setSessionTrackingModes( sessionConfig.getSessionTrackingModes()); } } ................. ................. ................. } ................. ................. ................. }
org/apache/tomcat/util/descriptor/web/WebRuleSet.java
/session-config/cookie-config/max-age为web.xml的配置项
/** * <p>Add the set of Rule instances defined in this RuleSet to the * specified <code>Digester</code> instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.</p> * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { ................. ................. ................. digester.addRule(fullPrefix + "/session-config", sessionConfig); digester.addObjectCreate(fullPrefix + "/session-config", "org.apache.tomcat.util.descriptor.web.SessionConfig"); digester.addSetNext(fullPrefix + "/session-config", "setSessionConfig", "org.apache.tomcat.util.descriptor.web.SessionConfig"); digester.addCallMethod(fullPrefix + "/session-config/session-timeout", "setSessionTimeout", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/name", "setCookieName", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/domain", "setCookieDomain", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/path", "setCookiePath", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/comment", "setCookieComment", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/http-only", "setCookieHttpOnly", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/secure", "setCookieSecure", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/max-age", "setCookieMaxAge", 0); digester.addCallMethod(fullPrefix + "/session-config/tracking-mode", "addSessionTrackingMode", 0); ................. ................. ................. }
从上面的addRuleInstances里看出session cookie maxage的配置在工程里的web.xml的session-config里,比如:
<session-config> # 设置Session数据30分钟后过期-服务端 <session-timeout>30</session-timeout> <cookie-config> # 设置SessionId在Cookie中的名称 <name>sop_session_id</name> # 设置SessionId存在哪个路径下,跟路径则可全站使用 <path>/</path> # 设置是否只读 <http-only>true</http-only> # 设置SessionId30分钟后过期 <max-age>1800</max-age> # 设置安全机制,只有https才能获取 <secure>true</secure> </cookie-config> </session-config>
疑问:如果session-timeout和max-age我都设置1年,那不是一年都不用登录了?