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>