设为首页 收藏本站
查看: 796|回复: 0

[经验分享] tomcat对sessionId的处理分析

[复制链接]

尚未签到

发表于 2015-8-11 05:27:10 | 显示全部楼层 |阅读模式
  
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(&quot; Requested cookie session id is &quot; +
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(&quot;coyoteRequest.sessionCreateCommitted&quot;));
}
// 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 ((&quot;/&quot;.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(&quot;managerBase.createSession.ise&quot;));
}
// 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 = &quot;Set-Cookie&quot;;
final String startsWith = name + &quot;=&quot;;
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中。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-97141-1-1.html 上篇帖子: 部署tomcat应用的三种方法 下篇帖子: 在tomcat下配置jdbc连接池点滴
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表