使用session监听+spring MVC拦截器禁止用户重复登录
在許多web項目中,需要禁止用戶重復登錄。一般來說有兩種做法:
???????? 一是在用戶表中維護一個字段isOnLine(是否在線),用戶登錄時,設定值為true,用戶退出時設定為false,在重復登錄時,檢索到該字段為true時,禁止用戶登錄。這種方法有明顯的漏洞,及用戶在非正常情況退出(關閉瀏覽器、關機等)是,該字段值一直為true,會導致用戶無法登錄。
????????? 而另一種比較通用的做法是使用session監聽,重復登錄后,強制之前登錄的session過期,從而踢出了該用戶。具體做法是:使用監聽器維護服務器上緩存的sessionMap,該map是以<session.getId(),session>的鍵值對,在登錄后,使用userid替換session.getId(),從而使得sessionMap中維護的是<userid, session>的鍵值對。后續該帳號重復登錄時,檢索到已有該帳號session則強制它過期。
???
1、web.xml中配置session監聽
<listener><listener-class>com.cnpc.framework.listener.SessionListener</listener-class> </listener>2、session監聽SessionListener類 package com.cnpc.framework.listener;import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener;import com.cnpc.framework.utils.SessionContext;public class SessionListener implements HttpSessionListener {public static SessionContext sessionContext=SessionContext.getInstance();public void sessionCreated(HttpSessionEvent httpSessionEvent) {sessionContext.AddSession(httpSessionEvent.getSession());}public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {sessionContext.DelSession(httpSessionEvent.getSession());} } SessionContex類(使用單例模式) package com.cnpc.framework.utils;import java.util.HashMap;import javax.servlet.http.HttpSession;public class SessionContext {private static SessionContext instance;private HashMap<String,HttpSession> sessionMap;private SessionContext() {sessionMap = new HashMap<String,HttpSession>();}public static SessionContext getInstance() {if (instance == null) {instance = new SessionContext();}return instance;}public synchronized void AddSession(HttpSession session) {if (session != null) {sessionMap.put(session.getId(), session);}}public synchronized void DelSession(HttpSession session) {if (session != null) {sessionMap.remove(session.getId());if(session.getAttribute("userid")!=null){sessionMap.remove(session.getAttribute("userid").toString());//session.invalidate(); }}}public synchronized HttpSession getSession(String session_id) {if (session_id == null) return null;return (HttpSession) sessionMap.get(session_id);}public HashMap getSessionMap() {return sessionMap;}public void setMymap(HashMap sessionMap) {this.sessionMap = sessionMap;}}
3、用戶登錄成功后,更新session Map,如重復登錄,強制之前session過期
public void sessionHandlerByCacheMap(HttpSession session){String userid=session.getAttribute("userid").toString();if(SessionListener.sessionContext.getSessionMap().get(userid)!=null){HttpSession userSession=(HttpSession)SessionListener.sessionContext.getSessionMap().get(userid);//注銷在線用戶userSession.invalidate(); SessionListener.sessionContext.getSessionMap().remove(userid);//清除在線用戶后,更新map,替換map sessionidSessionListener.sessionContext.getSessionMap().remove(session.getId()); SessionListener.sessionContext.getSessionMap().put(userid,session); }else{// 根據當前sessionid 取session對象。 更新map key=用戶名 value=session對象 刪除mapSessionListener.sessionContext.getSessionMap().get(session.getId());SessionListener.sessionContext.getSessionMap().put(userid,SessionListener.sessionContext.getSessionMap().get(session.getId()));SessionListener.sessionContext.getSessionMap().remove(session.getId());}}4、spring MVC攔截器校驗session是否過期,如果過期,給出提示,并跳轉到登錄界面。?
??? 攔截器配置??
web.xml配置
攔截器authInterceptor package com.cnpc.framework.interceptor;import java.io.PrintWriter; import java.util.Map;import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Component; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import com.cnpc.framework.common.SessionContainer;("SpringMVCInterceptor") public class AuthInterceptor extends HandlerInterceptorAdapter { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");//過濾登錄、退出訪問String[] noFilters = new String[] { "/auth/login", "/auth/logout" };String uri = request.getRequestURI();boolean beFilter = true;for (String s : noFilters) {if (uri.indexOf(s) != -1) {beFilter = false;break;}}SessionContainer sessionContainer = (SessionContainer) request.getSession().getAttribute("SessionContainer");if (beFilter) {if (null == sessionContainer) {//ajax方式交互if (request.getHeader("x-requested-with") != null&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))// 如果是ajax請求響應頭會有,x-requested-with;{ response.setHeader("sessionstatus", "timeout");// 在響應頭設置session狀態return false;}// 未登錄PrintWriter out = response.getWriter();StringBuilder builder = new StringBuilder();builder.append("<script type=\"text/javascript\" charset=\"UTF-8\">");builder.append("alert(\"頁面過期,請重新登錄\");");builder.append("window.top.location.href='/auth/logout';");builder.append("</script>");out.print(builder.toString());out.close();return false;} else { // 添加系統日志// -----------------------------------// -----------------------------------}}Map paramsMap = request.getParameterMap();return super.preHandle(request, response, handler);} }
以上Sprring MVC攔截器在同服務器以ajax方式交互時,前臺需做如下相應處理: //控制ajax請求,session超時處理頁面跳轉$.ajaxSetup({ contentType:"application/x-www-form-urlencoded;charset=utf-8", complete:function(XMLHttpRequest,textStatus){ var sessionstatus=XMLHttpRequest.getResponseHeader("sessionstatus"); // 通過XMLHttpRequest取得響應頭,sessionstatus,if(sessionstatus=="timeout"){ // 如果超時就處理 ,指定要跳轉的頁面 alert("頁面過期,請重新登錄"); window.top.location.href="/auth/logout";} } } );
?????????? 以上方式完成了禁止用戶重復登錄的功能,并將踢出之前登錄的帳號,這在不同的瀏覽器中使用沒有問題。但是因為在同一個瀏覽器中,多個標簽頁(Tab頁)是共享session的,在同一個瀏覽器中并不會創建一個新的session。所以同一個瀏覽器還是可以重復登錄的,目前還沒有什么很好解決辦法。本來想如果重復登錄,則通過校驗session是否存在來禁止登錄。但是之前登錄的若關閉了標簽頁,則在這個瀏覽器上的其他標簽頁則再也無法登錄了。所以這個做法也有問題。
from:?http://blog.csdn.net/jrn1012/article/details/25781319
https://my.oschina.net/pangzhuzhu/blog/318012
總結
以上是生活随笔為你收集整理的使用session监听+spring MVC拦截器禁止用户重复登录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jmeter教程 简单的压力测试
- 下一篇: C++ 虚函数和纯虚函数的区别