如何做到同⼀个账号同⼀时段只能登录⼀个
在许多web 项⽬中,需要禁⽌⽤户重复登录。⼀般来说有两种做法:
⼀是在⽤户表中维护⼀个字段isOnLine(是否在线),⽤户登录时,设定值为true ,⽤户退出时设定为false ,在重复登录时,检索到该字段为true 时,禁⽌⽤户登录。这种⽅法有明显的漏洞,及⽤户在⾮正常情况退出(关闭浏览器、关机等)是,该字段值⼀直为true ,会导致⽤户⽆法登录。
⽽另⼀种⽐较通⽤的做法是使⽤session 监听,重复登录后,强制之前登录的session 过期,从⽽踢出了该⽤户。具体做法是:使⽤维护服务器上缓存的sessionMap ,该map 是以&Id(),session>的键值对,在登录后,使⽤userid 替换Id(),从⽽使得sessionMap 中维护的是<userid, session>的键值对。后续该帐号重复登录时,检索到已有该帐号session 则强制它过期。
1、l 中配置session 监听
2、session 监听SessionListener 类
SessionContex 类(使⽤单例模式)[html]
01. <listener> 02. <listener-class>compc.framework.listener.SessionListener </listener-class> 03. </listener> [html]
01. package compc.framework.listener; 02. 03. import javax.servlet.http.HttpSessionEvent; 04. import javax.servlet.http.HttpSessionListener; 05. 06. import compc.framework.utils.SessionContext; 07. 08. public class SessionListener implements HttpSessionListener { 09. public static SessionContext sessionContext =SessionContext .getInstance(); 10. 11. public void sessionCreated(HttpSessionEvent httpSessionEvent) { 12. sessionContext.Session()); 13. } 14. 15. public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { 16. sessionContext.Session()); 17. } 18. } [html]session如何设置和读取
01. package compc.framework.utils; 02. 03. import java.util.HashMap; 04. 05. import javax.servlet.http.HttpSession; 06. 07. 08. public class SessionContext { 09. private static SessionContext instance; 10. private HashMap <String ,HttpSession > sessionMap; 11. 12. private SessionContext() { 13. sessionMap = new HashMap <String ,HttpSession >(); 14. } 15. 16. public static SessionContext getInstance() { 17. if (instance == null) { 18. instance = new SessionContext(); 19. } 20. return instance; 21. } 22. 23. public sync
hronized void AddSession(HttpSession session) { 24. if (session != null) { 25. sessionMap.Id(), session); 26. } 27. } 28.
3、⽤户登录成功后,更新session Map ,如重复登录,强制之前session 过期
4、spring MVC 校验session 是否过期,如果过期,给出提⽰,并跳转到登录界⾯。
配置
authInterceptor 29. public synchronized void DelSession(HttpSession session) { 30. if (session != null) { 31. Id()); 32. Attribute("userid")!=null){ 33. Attribute("userid").toString()); 34. //session.invalidate(); 35. } 36. } 37. } 38. 39. public synchronized HttpSession getSession(String session_id) { 40. if (session_id == null) return null; 41. return (HttpSession) (session_id); 42. } 43. 44. public HashMap getSessionMap() { 45. return s
essionMap; 46. } 47. 48. public void setMymap(HashMap sessionMap) { 49. this.sessionMap = sessionMap ; 50. } 51. 52. } [html]
01. public void sessionHandlerByCacheMap(HttpSession session){ 02. String userid =session .getAttribute("userid").toString(); 03. if(SessionMap().get(userid)!=null){ 04. HttpSession userSession =(HttpSession)SessionMap().get(userid); 05. //注销在线⽤户 06. userSession.invalidate(); 07. SessionMap().remove(userid); 08. //清除在线⽤户后,更新map,替换map sessionid 09. SessionMap().Id()); 10. SessionMap().put(userid,session); 11. } 12. else 13. { 14. // 根据当前sessionid 取session 对象。 更新map key =⽤户名 value =session 对象 删除map 15. SessionMap().Id()); 16. SessionMap().put(userid,SessionMap().Id())17. SessionMap().Id()); 18. } 19. }
[html]
01. <init-param> 02. <description>Spring MVC 配置⽂件</description> 03. <param-name>contextConfigLocation </param-name> 04. <param-value>l </param-value> 05. </init-param>
[html]
01. <mvc:interceptors> 02. <bean class ="compc.framework.interceptor.AuthInterceptor" /> 03. </mvc:interceptors>
[html]
01. package compc.framework.interceptor; 02. 03. import java.io.PrintWriter;
以上Sprring MVC 在同服务器以ajax ⽅式交互时,前台需做如下相应处理:04. import java.util.Map; 05. 06. import javax.annotation.Resource; 07. import javax.servlet.http.HttpServletRequest; 08. import javax.servlet.http.HttpServletResponse; 09. 10. import org.springframework.stereotype.Component; 11. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 12. 13. import compc.fram
eworkmon.SessionContainer; 14. 15. @Component("SpringMVCInterceptor") 16. public class AuthInterceptor extends HandlerInterceptorAdapter { 17. 18. @Override 19. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 20. request.setCharacterEncoding("UTF-8"); 21. response.setCharacterEncoding("UTF-8"); 22. response.setContentType("text/html;charset =UTF -8"); 23. 24. //过滤登录、退出访问 25. String[] noFilters = new String[] { "/auth/login", "/auth/logout" }; 26. String uri = request .getRequestURI(); 27. 28. boolean beFilter = true ; 29. for (String s : noFilters) { 30. if (uri.indexOf(s) != -1) { 31. beFilter = false ; 32. break; 33. } 34. } 35. SessionContainer sessionContainer = (SessionContainer) Session().getAttribute("SessionContainer"); 36. if (beFilter) { 37. if (null == sessionContainer) { 38. //ajax ⽅式交互 39. if (Header("x-requested-with") != null 40.
&& Header("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))// 如果是ajax 请求响应头会有,x-requested-with ; 41. { 42. response.setHeader("sessionstatus", "timeout");// 在响应头设置session 状态 43. return false; 44. } 45. // 未登录 46. PrintWriter out = response .getWriter(); 4
7. StringBuilder builder = new StringBuilder(); 48. builder.append("<script type =\"text/javascript\" charset =\"UTF-8\">"); 49. builder.append("alert(\"页⾯过期,请重新登录\");"); 50. builder.append("p.location.href ='/auth/logout';"); 51. builder.append("</script>"); 52. out.String()); 53. out.close(); 54. return false; 55. } else { 56. // 添加系统⽇志 57. // ----------------------------------- 58. // ----------------------------------- 59. } 60. } 61. Map paramsMap = request .getParameterMap(); 62. return super.preHandle(request, response, handler); 63. } 64. }
[html]
01. //控制ajax 请求,session 超时处理页⾯跳转 02. $.ajaxSetup({ 03. contentType:"application/x-www-form-urlencoded;charset =utf -8", 04. complete:function(XMLHttpRequest,textStatus){ 05.
var sessionstatus =XMLHttpRequest .getResponseHeader("sessionstatus"); // 通过XMLHttpRequest 取得响应头,sessionstatus , 06. if(sessionstatus =="timeout"){ 07. // 如果超时就处理 ,指定要跳转的页⾯ 08. alert("页⾯过期,请重新登录"); 09. p.location.href ="/auth/logout"; 10. }
以上⽅式完成了禁⽌⽤户重复登录的功能,并将踢出之前登录的帐号,这在不同的浏览器中使⽤没有问题。但是因为在同⼀个浏览器中,多个标签页(Tab 页)是共享session 的,在同⼀个浏览器中并不会创建⼀个新的session 。所以同⼀个浏览器还是可以重复登录的,⽬前还没有什么很好解决办法。本来想如果重复登录,则通过校验session 是否存在来禁⽌登录。但是之前登录的若关闭了标签页,则在这个浏览器上的其他标签页则再也⽆法登录了。所以这个做法也有问题。11. } 12. } 13. );
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论