`
hpt321
  • 浏览: 9321 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

应用memcached保存session会话信息

阅读更多

小弟做了一个应用memcached来保存session会话信息的程序,还请各位大哥指点一下:
大致思路如下:
1、把sessionId存放在cookie中,并设定一个有效期;
2、把经过Serializable序列化的对象存放在memcached中,同时设置一个失效时间,比如1小时;
3、每次取会话信息时,先从cookie中取sessionId,如果cookie不存在,则说明会话已过期;如果会话存在,则从memcached中读取会话信息,如果会话信息不存在,则从数据库中读取相关信息,然后放在memcached中,同时设置失效时间;
4、设置一个filter,在每次请求时,更新会话cookie的失效时间;
5、登录时设置一个隐藏的随机数;
6、退出时删除会话cookie,同时从memcached中删除相关的会话;

如需所有的源码,可以发送电子邮件:hpt321@163.com .

代码如下:

RequestUtils.java

package com.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**

*对cookie读写

*/

public class RequestUtils
{

 public static String cookieDomain = "";

 public static String cookiePath = "/";
 
 /**
  * 获取COOKIE
  * @param request
  * @param name
  */
 public static Cookie getCookie(HttpServletRequest request, String name) {
  Cookie[] cookies = request.getCookies();
  if(cookies == null)
   return null;
  for (int i = 0; i < cookies.length; i++) {
   if (name.equals(cookies[i].getName())) {
    return cookies[i];
   }
  }
  return null;
 }

 /**
  * 设置COOKIE
  * @param request
  * @param response
  * @param name
  * @param value
  * @param maxAge
  */
 public static void setCookie(HttpServletRequest request, HttpServletResponse response, String name,
   String value, int maxAge)
 {
  Cookie cookie = new Cookie(name, value);
  cookie.setMaxAge(maxAge);
  if(cookieDomain!=null && cookieDomain.indexOf('.')!=-1){
   cookie.setDomain('.' + cookieDomain);
  }
  cookie.setPath(cookiePath);
  response.addCookie(cookie);
 }
 }

//

SessionCookieFilter.java

package com.mem.session;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.RequestUtils;

/**

*对每次动态页面的请求时,更新会话cookie的有效期

*/

public class SessionCookieFilter extends HttpServlet implements Filter
{
 /**
  *
  */
 private static final long serialVersionUID = -6516046520244652987L;

 private String sessionId = "sid";
 
 private int expiryDate = 30*60;//seconeds
 
 public void doFilter(ServletRequest servletRequest,
   ServletResponse servletResponse, FilterChain filterChain)
   throws IOException, ServletException
 { 
  HttpServletRequest request = (HttpServletRequest) servletRequest;
  HttpServletResponse response = (HttpServletResponse) servletResponse;
  Cookie cookie = RequestUtils.getCookie(request, sessionId); 
  if (cookie != null)
  {
   String sid = cookie.getValue();
   //设置cookie的有效期
   RequestUtils.setCookie(request, response, sessionId, sid, expiryDate);
  }
  filterChain.doFilter(request,response);
 }

 public void init(FilterConfig filterConfig) throws ServletException
 {
  this.sessionId = filterConfig.getInitParameter("sessionId");
 
  com.util.RequestUtils.cookieDomain = filterConfig.getInitParameter("cookieDomain");
  if (com.util.RequestUtils.cookieDomain == null)
  {
   com.util.RequestUtils.cookieDomain = "";
  }

  com.util.RequestUtils.cookiePath = filterConfig.getInitParameter("cookiePath");
  if (com.util.RequestUtils.cookiePath == null || com.util.RequestUtils.cookiePath.length() == 0)
  {
   com.util.RequestUtils.cookiePath = "/";
  }
 }

}

//

SessionService.java

package com.mem.session;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Calendar;
import java.util.Date;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

/**

*对memcached的操作

*/

public class SessionService {

 private static SessionService instance = null;

 private SockIOPool pool = null;

 private String poolName = "sidsock";
 
 private int expiryTime = 60;//minutes
 
 private Date getExpiryDate()
 {
  Calendar calendar = Calendar.getInstance();
 
  long time = calendar.getTimeInMillis();
  time += expiryTime * 60 * 1000;
  calendar.setTimeInMillis(time);
 
  return calendar.getTime();
 }

 public static synchronized SessionService getInstance() {
  if (instance == null) {
   instance = new SessionService();
  }
  return instance;
 }

 private SessionService() {
  ClassLoader cl = Thread.currentThread().getContextClassLoader();
  InputStream input = cl.getResourceAsStream("memcached.properties");
  Properties props = new Properties();
  String serverlist = "127.0.0.1:11211";
  try {
   props.load(input);
   serverlist = props.getProperty("serverlist", "127.0.0.1:11211");
   poolName = props.getProperty("poolname", "sidsock");

  } catch (Exception e) {
   e.printStackTrace();
  }

  String[] servers = serverlist.split(",");
  pool = SockIOPool.getInstance(poolName);
  pool.setServers(servers);
  pool.setFailover(true);
  pool.setInitConn(10);
  pool.setMinConn(5);
  pool.setMaxConn(250);
  pool.setMaintSleep(30);
  pool.setNagle(false);
  pool.setSocketTO(3000);
  pool.setAliveCheck(true);
  pool.initialize();
 }

 public boolean sessionExists(String id)
 {
  MemCachedClient mc = this.getMemCachedClient();
  return  mc.keyExists(id);
 }
 public Map getSession(String id,boolean create)
 {
  MemCachedClient mc = this.getMemCachedClient();
 
  Map session = (Map) mc.get(id);
  if(session == null)
  {
   if(create)
   {
    session = new HashMap(5);
    mc.add(id, session,getExpiryDate());
   }
  }
  return session;
 }

 public void saveSession(String id, Map session)
 {
  MemCachedClient mc = this.getMemCachedClient();
  if(mc.keyExists(id))
  {
   mc.replace(id, session);
  }
  else
  {
   mc.add(id, session);
  }
 }
 
 public void saveSession(String id, Map session,Date expiryDate)
 {
  MemCachedClient mc = this.getMemCachedClient();
  if(mc.keyExists(id))
  {
   mc.replace(id, session,expiryDate);
  }
  else
  {
   mc.add(id, session,expiryDate);
  }
 }

 public void removeSession(String id)
 {
  MemCachedClient mc = this.getMemCachedClient();
  mc.delete(id);
 }

 public void updateExpiryDate(String id)
 {
  MemCachedClient mc = this.getMemCachedClient();
  Map session = (Map) mc.get(id);
  if(session != null)
  {
   mc.replace(id, session,getExpiryDate());
  }
 }
 
 private MemCachedClient getMemCachedClient()
 {
  MemCachedClient mc = new MemCachedClient();
  mc.setPoolName(poolName);
  mc.setCompressEnable(false);
  mc.setCompressThreshold(0);
  return mc;
 }

 protected void finalize()
 {
  if (this.pool != null)
  {
   this.pool.shutDown();
  }
 }

}


//

MemSession.java

package com.mem.session;

import java.util.Map;

/**

*对会话的操作

*/

public class MemSession
{
 //会话ID
 private String sid = "";

 //存放本会话的所有信息
 private Map map = null;
 
 public static MemSession getSession(String sid)
 {
  MemSession session = null;
 
  session = new MemSession(sid,true);
 
  return session;
 }
 
 public static MemSession getSession(String sid,boolean create)
 {
  MemSession session = null;
 
  session = new MemSession(sid,create);
 
  return session;
 }

 private MemSession(String sid,boolean create)
 {
  this.sid = sid;
  this.map = SessionService.getInstance().getSession(sid,create);
 }

 public static boolean sessionExists(String sid)
 {
  return SessionService.getInstance().sessionExists(sid);
 }
 
 public Object getAttribute(String arg0)
 {
  return this.map.get(arg0);
 }

 public void invalidate()
 {
  this.map.clear();
  SessionService.getInstance().removeSession(this.sid);
 }

 public void removeAttribute(String arg0)
 {
  if(arg0 == null || arg0.trim().length() <= 0)
  {
   return;
  }
  this.map.remove(arg0);
  SessionService.getInstance().saveSession(this.sid, this.map);
 }
 public void setAttribute(String arg0, Object arg1)
 {
  if(arg0 == null || arg0.trim().length() <= 0 || arg1 == null)
  {
   return ;
  }
  this.map.put(arg0, arg1);
  SessionService.getInstance().saveSession(this.sid, this.map);
 }
 public void updateExpiryDate(String sid)
 {
  SessionService.getInstance().updateExpiryDate(sid);
 }
 
}


//SessionUtil.java

package com.mem.session;

import java.io.Serializable;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.RequestUtils;
import com.mem.session.MemSession;

public class SessionUtil
{
 public static UserInfo getUserInfo(HttpServletRequest request)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
 
  if(cookie != null)
  {
   String sid = cookie.getValue();
   MemSession session = MemSession.getSession(sid);
   UserInfo userInfo = (UserInfo)session.getAttribute("user_session_flag");
  
   if(userInfo == null)
   {
    //缓存中已经不存在,则要从数据库中读取,同时存放在缓存中
    userInfo = new UserInfo("hpt321",1,"hpt321");//要从数据库中读取
    session.setAttribute("user_session_flag", userInfo);
   
    return userInfo;
   }
  
  }
  return null;
 }
 
 public static void setUserInfo(UserInfo userInfo,HttpServletRequest request,HttpServletResponse response)
 {
  setAttribute(request, "user_session_flag", userInfo);
 }
 /**
  * 登录返回true;未登录返回false;
  * @param request
  * @return
  */
 public static boolean valideLogin(HttpServletRequest request)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
  if(cookie == null)
  {
   return false;
  }
  else
  {
   return true;
  }
 }
 public static void setAttribute(String sid,String key,Object value)
 {
  //把置放入缓存中
  MemSession session = MemSession.getSession(sid);
  session.setAttribute(key, value);
 }
 public static void setAttribute(HttpServletRequest request,String key,Object value)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
  if(cookie != null)
  {
//   取出session的ID
   String sid = cookie.getValue();
   //把置放入缓存中
   MemSession session = MemSession.getSession(sid);
   session.setAttribute(key, value);
  }
 }
 public static Object getAttribute(String sid,String key)
 {
  //把置放入缓存中
  MemSession session = MemSession.getSession(sid);
  return session.getAttribute(key); 
 }
 public static Object getAttribute(HttpServletRequest request,String key)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
 
  if(cookie != null)
  {
   //取出session的ID
   String sid = cookie.getValue();
   //把置放入缓存中
   MemSession session = MemSession.getSession(sid);
   return session.getAttribute(key); 
  }
  return null;
 }
 public static void removeAttribute(HttpServletRequest request,String key)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
 
  if(cookie != null)
  {
   //取出session的ID
   String sid = cookie.getValue();
   //把置放入缓存中
   MemSession session = MemSession.getSession(sid);
   session.removeAttribute(key);
  }
 
 }
 public static void invalidate(HttpServletRequest request)
 {
  Cookie cookie = RequestUtils.getCookie(request, "sid");
 
  if(cookie != null)
  {
   //取出session的ID
   String sid = cookie.getValue();
   //把置放入缓存中
   MemSession session = MemSession.getSession(sid);
   session.invalidate();
  }
 }
 
}

//
登录
synchronized(信号量)
{
 //验证隐藏的验证码,同时删除随机验证码,避免重复登录
}

//1、此处先得到cookie中已有的会话ID,以便登录后清除memached中的会话信息;

//2、清除前一个登录的会话信息


String sid = java.util.UUID.randomUUID().toString()+serverName+"_"+userId;
//加入serverName,是为了区分多台服务器产生的randomUUID可能相同

  com.util.RequestUtils.setCookie(request, response, "sid", sid, 30*60); 
  
  com.mem.session.SessionUtil.setAttribute(sid, "user_session_flag", userInfo);

 

//退出

删除会话cookie同时删除memcached中的会话信息

com.mem.session.SessionUtil.invalidate(request);

分享到:
评论
12 楼 liuweiqq2008 2008-04-30  
问多台服务器memcached session掉线原因
11 楼 ithero 2007-11-03  
hpt321 写道
如果设置失效时间,不能存放逻辑数据,如果不设置失效时间,应该还有另外一个程序处理失效的session。

memcached如果你设置了失效时间。正常情况下。你的代码需要同时维护cookie与memcached失效时间。用户每次调用后都需要去更新cookied与memecached的失效时间。发现只有包装session。HttpSesssionWrapper.依然交由容器来维护。个人感觉这样代码重要性要高,性能上可能也要更高些吧,这只是没经测试的个人想法,可能有误。。
10 楼 hpt321 2007-11-02  
如果设置失效时间,不能存放逻辑数据,如果不设置失效时间,应该还有另外一个程序处理失效的session。
9 楼 hpt321 2007-11-02  
这几天收到大家的来信,由于比较忙,没有及时向大家回复,在此表示抱歉。
有的回复了,有的没回复,今天就把原码粘贴到附件中了,大家共同讨论,共同研究!
未来总是人类慢慢发掘的!
8 楼 acdc 2007-11-02  
ithero 写道
很多网站都是采用这种方式.javaeye的session也是采用这种方式.4楼的可以试试.这种潜在的问题确实有可能存在.4楼的朋友平时应该经常在黑圈中出没吧.id可以用des加个key来加密.取的时候再解密.这年头没有绝对的安全.除非你把网线扯掉了


DES/DES3似乎也没太大难度去暴力破解。
其实我提出这个问题,就是想引出我的看法,Session管理很有讲究的。
通常Session Cookie是用RSA/DSA签名+ AES128加密的。服务器端则需要有一个比较安全的机制来维护这些Session有效期。。。

我看到了这么多朋友青睐memcached,这么多朋友谈SNA,但是我似乎还没有看到有哪个基于Memcachd的SNA方案,可以安全的管理Session
7 楼 acdc 2007-11-02  
ben.lee 写道
建议Id用md5加密,应该就没问题了。
还有楼上说的也可以到

单向的hash有啥意义?Id而已,表明身份的,在加密也是个id串
6 楼 ithero 2007-11-02  
很多网站都是采用这种方式.javaeye的session也是采用这种方式.4楼的可以试试.这种潜在的问题确实有可能存在.4楼的朋友平时应该经常在黑圈中出没吧.id可以用des加个key来加密.取的时候再解密.这年头没有绝对的安全.除非你把网线扯掉了
5 楼 ben.lee 2007-11-01  
建议Id用md5加密,应该就没问题了。
还有楼上说的也可以到
4 楼 acdc 2007-11-01  
hpt321 写道
sessionId是存放在cookie中的,除非你能改该domain下的cookie;关闭Browser后,在有效期内再次打开还是登录状态,可以在退出时清除cookie


很简单。假如你的系统是ABC.COM
1. 用live http headers之类工具,访问真正的abc.com,了解到登陆后,服务器会写那些cookie
2. 本地架设一台服务器,上跑一脚本程序,可以把同样的cookie发送给browser.
3. 开始sniffr其他用户数据报,发现到sessionID
4. 将该sessionID发送给local server,同时修改本地host文件把abc.com指向改本地的http server.访问local server上的脚本,写入cookie
5. 恢复host文件,开始访问真正的abc.com

以上只是为了解释方便,一一把步骤写下来,其实可以自动化完成....

所以cookie还是要加密的,而且session timeout不能依靠cookie的lifecycle来实现
3 楼 hpt321 2007-11-01  
sessionId是存放在cookie中的,除非你能改该domain下的cookie;关闭Browser后,在有效期内再次打开还是登录状态,可以在退出时清除cookie
2 楼 acdc 2007-10-31  
请问如果我探测了那个sessionId,是否就可以伪造登录了?

> 把sessionId存放在cookie中,并设定一个有效期;
我关闭了Browser,只要在有效期内,再次打开,我还是登录的?
1 楼 Heraclesun 2007-10-24  
拜读研究中

相关推荐

    nginx+tomcat7+memcached session会话保持

    在构建高性能、高可用性的Web应用系统时,会话保持是一个关键环节,它涉及到用户登录状态、购物车信息等重要数据的持久化处理。本文将详细介绍如何在Nginx、Tomcat7和Memcached的环境下实现会话保持,确保用户在多台...

    session共享 memcached-session-manager 1.9.6 jar

    `memcached-session-manager`是Java的一个库,用于在基于Tomcat的Web应用中实现基于Memcached的session共享,这在分布式环境中尤为重要。 标题中的"session共享 memcached-session-manager 1.9.6 jar"指的正是这个...

    Memcached_Session_Manager jar

    **Memcached_Session_Manager jar** 是一个专为Tomcat服务器设计的组件,用于管理Web应用程序的会话(Session)。会话管理在多服务器环境,特别是集群环境中尤为重要,因为需要确保用户在集群中的任何一台服务器上都...

    memcached管理session资源

    MSM(Memcached_Session_Manager)是一个基于Java的Memcached会话管理器,它允许我们将Web应用的session数据存储在Memcached服务器上,而不是传统的保存在服务器的内存中或者硬盘上的session文件。这样,即使服务器...

    memcached-session-manager

    "memcached-session-manager" 是一个与Web应用程序相关的组件,它主要用于管理用户的会话(session)。Memcached 是一个高性能、分布式内存对象缓存系统,常用于减轻数据库的负载,通过将数据存储在内存中来加速访问...

    tomcat8+memcached session共享

    在分布式系统中,session共享是一个重要的问题,因为用户在访问不同的服务器节点时,需要保持登录状态和其他会话信息的一致性。Memcached作为一个高性能的分布式内存对象缓存系统,常被用来解决这个问题。 描述中...

    memcached-session-manager-1.6.5.rar

    Memcached Session Manager 1.6.5是一款专门用于处理Web应用程序中的用户会话管理的工具,它基于Java平台,利用了高效的分布式缓存系统——Memcached。在Java Web开发中,会话管理是不可或缺的一部分,而传统的基于...

    Memcached-session-manager所需最新jar包-tomcat7-kryo序列

    3. **Memcached-session-manager**:这是一个开源项目,用于在Apache Tomcat应用服务器中集成Memcached,以便将用户的会话数据存储在Memcached集群中,以实现高可用性和可扩展性。它提供了一种替代默认的基于文件或...

    memcached session共享所用到的jar包

    这样做是因为这些库提供了Servlet监听器,可以在每次会话开始时注册,将新的会话保存到memcached,并在会话结束时清除。 4. **配置Servlet容器**:在Tomcat的`context.xml`或`web.xml`配置文件中,我们需要添加相应...

    memcached-session-manager集成包

    `memcached-session-manager` 是一个专为Tomcat设计的组件,它允许将Web应用的会话信息存储在memcached分布式缓存系统中,从而实现会话的跨服务器共享,提高系统的可扩展性和性能。这个集成包是经过精心测试的,确保...

    memcached共享session需要的jar包

    在Java应用中,通过特定的jar包可以实现session的跨服务器共享,确保用户会话在集群中的各个节点间保持一致。 描述虽然简洁,但我们可以从中理解到,这个压缩包包含了实现这一功能所需的各种依赖库。接下来,我们将...

    memcached-session-manager+tomcat8.5_memcached-1.9.6.zip

    memcached-1.9.6,libevent-2.1.12-stable.tar memcached-session-manager-1.9.6,msm-kryo-serializer-1.9.6.jar,tomcat8.5,实现会话共享

    nginx集成memcached-session-manager所需要的jar

    Memcached-session-manager是Java应用程序,用于在Tomcat或其他基于Servlet的容器中管理会话,并将其存储在Memcached中,以实现会话的分布式和高可用性。 首先,我们需要理解会话管理在Web应用中的重要性。会话允许...

    tomcat8 memcached session共享jar包

    在Tomcat这样的Java应用服务器中,session管理是关键部分,它负责保存用户的会话状态。当有多台Tomcat服务器时,session共享能确保用户在集群中的任何一台服务器上都能保持登录状态和其他会话信息。 描述提到...

    memcached-session-manager-1.8.1

    Memcached Session Manager(MSM)是Java环境下的一种解决方案,它利用高效、分布式缓存系统——Memcached来存储和管理HTTP会话,从而减轻服务器的压力并提高应用的可扩展性。本文将深入探讨Memcached Session ...

    j2ee项目使用filter和memcached实现session服务器

    在J2EE应用程序中,处理用户会话是至关重要的,特别是在多服务器环境下,为了确保用户在不同服务器之间切换时能够保持其登录状态和购物车等信息。这就是session管理的用武之地。本项目通过结合使用Filter(过滤器)...

    tomcat8+memcached-session的连接1.9.6版本jar包

    首先,"memcached-session-manager-1.9.6.jar"是核心组件,它实现了将Tomcat的用户会话数据存储到Memcached中的功能。这个库提供了一种方法,使得当用户在集群中的不同服务器之间跳转时,其会话状态可以无缝地保持...

    memcached配置session共享依赖jar包集合

    在Java Web应用中,session通常用于保存用户的登录状态和其他临时信息。当系统扩展到多台服务器时,传统的session管理方式会导致会话信息丢失,因为session是基于单个服务器存储的。因此,通过Memcached实现session...

    memcached-session-manager tomcat相关jar

    `memcached-session-manager` 是一个为Java应用服务器,特别是Tomcat设计的组件,用于将Web应用程序的用户会话数据存储在分布式缓存系统中,如Memcached。通过这种方式,它可以有效地处理高并发和分布式环境中的会话...

    Memcached-Session-Manager多tomcat实现session共享配置

    **Memcached-Session-Manager与Tomcat集群中的Session共享** 在分布式系统中,尤其是在使用了多个Tomcat实例作为Web服务器的集群环境中,确保用户会话(Session)在各个节点之间共享是至关重要的。Memcached-...

Global site tag (gtag.js) - Google Analytics