会话互串Sessions mixed-up

场景:
1-打开一个Tab,用Admin登录系统
2-再打开一个Tab,用User登录系统
3-退回Admin的Tab,操作数据
此时的用户已经不是Admin而是User了。
※早期主流浏览器没有选项卡,开创选项卡浏览器的是国人二次开发的MyIE。

不理解Session与Cookie的先补补这部分知识。


浏览器的多选项卡之间是共有一个Session的,所以这种情况下一般需要通过以下方法来访问系统:
1)打开不同的浏览器,比如:IE、FF、Chrome
2)打开同一浏览器的多个窗口(不是Ctrl+N打开)
IE: File>New Session
FF: File>New Private Window(Ctrl+Shift+P)
Chrome: Menu>New incognito Window(Ctrl+Shift+N)

这两种方法只能针对开发测试的,对用户来说就有些牵强了。

如何让系统支持多用户在多选项卡间同时登陆?首先最基本的需要采用ACL权限控制来保证用户的权限不会越级,比如上边这个场景不至于普通User执行了Admin的操作。

其次需要让多个选项卡之间只允许一个用户登录。
1)过滤请求,如果访问的是登录页,查看Session中是否已有用户信息,直接跳向指定页。
HttpSession session = request.getSession();

User user = (User) session.getAttribute("LOGIN_USER_INFO");
if (user == null) {
  // Session Timeout
  response.sendRedirect("LOGIN_URL");
  return false;
} else {
  // Multiple or Repeated Login
  if ("LOGIN_URL".equals(request.getRequestURI())) {
    response.sendRedirect("HOME_URL");
    return false;
  }
}

2)成功登陆后新建一个会话,删除老的会话,可防御会话劫持Session Fixation / Hijacking。
HttpSession oldSession = request.getSession(false);

if (oldSession != null && !oldSession.isNew()) {

  // store the old session
  Enumeration attrNames = oldSession.getAttributeNames();
  Properties props = new Properties();
  if (attrNames != null) {
    while (attrNames.hasMoreElements()) {
      String key = (String) attrNames.nextElement();
      props.put(key, oldSession.getAttribute(key));
    }
  }

  // invalidate the old session
  oldSession.invalidate();

  // generate a new session
  HttpSession newSession = request.getSession(true);

  // copy the data of the old session into the new session
  attrNames = props.keys();
  while (attrNames.hasMoreElements()) {
    String key = (String) attrNames.nextElement();
    newSession.setAttribute(key, props.get(key));
  }
}


另外两个问题:
1)限制同一个用户在同一时间只能登录一次
这里说的不是SSO单点登录,而是防止一个账户多处登录
在服务器端存储一个User的会话Map<User, Session>(或存入DB)
创建一个HttpSessionListener来监听会话,如果该User的会话已经存在用新的会话替换它。

2)同一服务器多应用的会话管理
Tomcat使用JSESSIONID作为默认的Cookie键值来识别Session,也可以自定义该键值:
<Host name="localhost" appBase="webapps"...>
  <Context path="/appA" sessionCookieName="yourCookieName"/>
</Host>

猜你喜欢

转载自rensanning.iteye.com/blog/2281843