tomcat多域名共享cookie,共享session以及修改sessionCookieName的解決方案

最近把工程拆分爲多個模塊分別部署,使用了多個二級域名,面臨多個二級域名之間 session 不能共享的問題,帶來的麻煩就是用戶在主域名登陸,但由於多個域名 session 不能共享 ,因此無法進行登陸的操作,對一些功能有一些影響。


問題的原因如下:

Tomcat 下,不同的二級域名,Session 默認是不共享的,因爲 Cookie 名稱爲 JSESSIONID 的 Cookie 根域是默認是沒設置的,訪問不同的二級域名,其 Cookie 就重新生成,而 session 就是根據這個 Cookie 來生成的,所以在不同的二級域名下生成的 Session 也不一樣。

找到了其原因,就可根據這個原因對 Tomcat 在生成 Session 時進行相應的修改。


快速解決方案1:
在項目的/MET-INF/ 目錄下創建一個 context.xml 文件,內容爲:
1 2 <?xml version='1.0' encoding='UTF-8'?> <Context useHttpOnly='true' sessionCookiePath='/' sessionCookieDomain='.XXXX.com' />

Done!


快速解決方案2:

修改 Tomcat 的 server.xml 文件,內容爲:

1 <Context path='' docBase='ROOT' reloadable='false' useHttpOnly='true' sessionCookiePath='/' sessionCookieDomain='.XXXX.com' />
Done!

以上兩種方案的詳細講解見:http://tomcat.apache.org/tomcat-6.0-doc/config/context.html


快速解決方案3:

生成一個叫做 crossSubdomainSessionValve.jar 的文件,用的時候放在 Tomcat lib 目錄下,然後修改 Tomcat server.xml 文件:

1 <Valve className='me.seanchang.CrossSubdomainSessionValve' />
原理:取代由 Tomcat 域產生的會話 cookie ,允許該會話 cookie 跨子域共享。
代碼:
package me.seanchang; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.ServerCookie; public class CrossSubdomainSessionValve extends ValveBase { private static Logger log = Logger.getLogger('CrossSubdomainSessionValve'); public CrossSubdomainSessionValve() { super(); info = 'me.seanchang.CrossSubdomainSessionValve/1.0'; } @Override public void invoke(Request request, Response response) throws IOException, ServletException { // this will cause Request.doGetSession to create the session cookie if // necessary request.getSession(true); // replace any Tomcat-generated session cookies with our own Cookie[] cookies = response.getCookies(); if (cookies != null) {for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; log.info('CrossSubdomainSessionValve: Cookie name is ' + cookie.getName()); if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) replaceCookie(request, response, cookie); } } // process the next valve getNext().invoke(request, response); } protected void replaceCookie(Request request, Response response, Cookie cookie) { // copy the existing session cookie, but use a different domain Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue());if (cookie.getPath() != null) newCookie.setPath(cookie.getPath()); newCookie.setDomain(getCookieDomain(request)); newCookie.setMaxAge(cookie.getMaxAge()); newCookie.setVersion(cookie.getVersion()); if (cookie.getComment() != null) newCookie.setComment(cookie.getComment()); newCookie.setSecure(cookie.getSecure()); // if the response has already been committed, our replacement strategy // will have no effect MimeHeaders headers = new MimeHeaders(); if (response.isCommitted()) log.info('CrossSubdomainSessionValve: response was already committed!'); // find the Set-Cookie header for the existing cookie and replace its // value with new cookie headers = response.getCoyoteResponse().getMimeHeaders(); for (int i = 0, size = headers.size(); i < size; i++) { if (headers.getName(i).equals('Set-Cookie')) { MessageBytes value = headers.getValue(i); if (value.indexOf(cookie.getName()) >= 0) { StringBufferbuffer = new StringBuffer(); ServerCookie .appendCookieValue(buffer, newCookie.getVersion(), newCookie.getName(), newCookie.getValue(),newCookie.getPath(), newCookie.getDomain(), newCookie.getComment(), newCookie.getMaxAge(), newCookie.getSecure(), true); log.info('CrossSubdomainSessionValve: old Set-Cookie value: ' + value.toString()); log.info('CrossSubdomainSessionValve: new Set-Cookie value: ' + buffer); value.setString(buffer.toString()); } } }} protected StringgetCookieDomain(Request request) { String cookieDomain = request.getServerName(); String[] parts = cookieDomain.split('\\.'); if (parts.length >= 2) cookieDomain = parts[parts.length - 2] + '.' + parts[parts.length - 1]; return '.' + cookieDomain; } public StringtoString() turn ('CrossSubdomainSessionValve[container=' + container.getName() + ']'); } }
將以上代碼導出一個jar文件,放入 $CATALINA_HOME/lib 中,修改 $CATALINA_HOME/conf/server.xml 文件,加入:
1 <Valve className='me.seanchang.CrossSubdomainSessionValve' />

重啓 Tomcat ,Done !


附:修改sessionCookieName的方法:

tomcat6和tomcat7修改方法相同

在Context容器標籤上增加sessionCookieName參數

<Context path=”/” docBase=”webapp” reloadable=”false” sessionCookieName=”yoursessionname”></Context>




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章