使用session监听+spring MVC拦截器禁止用户重复登录
在許多web項(xiàng)目中,需要禁止用戶重復(fù)登錄。一般來(lái)說(shuō)有兩種做法:
???????? 一是在用戶表中維護(hù)一個(gè)字段isOnLine(是否在線),用戶登錄時(shí),設(shè)定值為true,用戶退出時(shí)設(shè)定為false,在重復(fù)登錄時(shí),檢索到該字段為true時(shí),禁止用戶登錄。這種方法有明顯的漏洞,及用戶在非正常情況退出(關(guān)閉瀏覽器、關(guān)機(jī)等)是,該字段值一直為true,會(huì)導(dǎo)致用戶無(wú)法登錄。
????????? 而另一種比較通用的做法是使用session監(jiān)聽,重復(fù)登錄后,強(qiáng)制之前登錄的session過(guò)期,從而踢出了該用戶。具體做法是:使用監(jiān)聽器維護(hù)服務(wù)器上緩存的sessionMap,該map是以<session.getId(),session>的鍵值對(duì),在登錄后,使用userid替換session.getId(),從而使得sessionMap中維護(hù)的是<userid, session>的鍵值對(duì)。后續(xù)該帳號(hào)重復(fù)登錄時(shí),檢索到已有該帳號(hào)session則強(qiáng)制它過(guò)期。
???
1、web.xml中配置session監(jiān)聽
<listener><listener-class>com.cnpc.framework.listener.SessionListener</listener-class> </listener>2、session監(jiān)聽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,如重復(fù)登錄,強(qiáng)制之前session過(guò)期
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{// 根據(jù)當(dāng)前sessionid 取session對(duì)象。 更新map key=用戶名 value=session對(duì)象 刪除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攔截器校驗(yàn)session是否過(guò)期,如果過(guò)期,給出提示,并跳轉(zhuǎn)到登錄界面。?
??? 攔截器配置??
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");//過(guò)濾登錄、退出訪問(wèn)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請(qǐng)求響應(yīng)頭會(huì)有,x-requested-with;{ response.setHeader("sessionstatus", "timeout");// 在響應(yīng)頭設(shè)置session狀態(tài)return false;}// 未登錄PrintWriter out = response.getWriter();StringBuilder builder = new StringBuilder();builder.append("<script type=\"text/javascript\" charset=\"UTF-8\">");builder.append("alert(\"頁(yè)面過(guò)期,請(qǐng)重新登錄\");");builder.append("window.top.location.href='/auth/logout';");builder.append("</script>");out.print(builder.toString());out.close();return false;} else { // 添加系統(tǒng)日志// -----------------------------------// -----------------------------------}}Map paramsMap = request.getParameterMap();return super.preHandle(request, response, handler);} }
以上Sprring MVC攔截器在同服務(wù)器以ajax方式交互時(shí),前臺(tái)需做如下相應(yīng)處理: //控制ajax請(qǐng)求,session超時(shí)處理頁(yè)面跳轉(zhuǎn)$.ajaxSetup({ contentType:"application/x-www-form-urlencoded;charset=utf-8", complete:function(XMLHttpRequest,textStatus){ var sessionstatus=XMLHttpRequest.getResponseHeader("sessionstatus"); // 通過(guò)XMLHttpRequest取得響應(yīng)頭,sessionstatus,if(sessionstatus=="timeout"){ // 如果超時(shí)就處理 ,指定要跳轉(zhuǎn)的頁(yè)面 alert("頁(yè)面過(guò)期,請(qǐng)重新登錄"); window.top.location.href="/auth/logout";} } } );
?????????? 以上方式完成了禁止用戶重復(fù)登錄的功能,并將踢出之前登錄的帳號(hào),這在不同的瀏覽器中使用沒(méi)有問(wèn)題。但是因?yàn)樵谕粋€(gè)瀏覽器中,多個(gè)標(biāo)簽頁(yè)(Tab頁(yè))是共享session的,在同一個(gè)瀏覽器中并不會(huì)創(chuàng)建一個(gè)新的session。所以同一個(gè)瀏覽器還是可以重復(fù)登錄的,目前還沒(méi)有什么很好解決辦法。本來(lái)想如果重復(fù)登錄,則通過(guò)校驗(yàn)session是否存在來(lái)禁止登錄。但是之前登錄的若關(guān)閉了標(biāo)簽頁(yè),則在這個(gè)瀏覽器上的其他標(biāo)簽頁(yè)則再也無(wú)法登錄了。所以這個(gè)做法也有問(wèn)題。
from:?http://blog.csdn.net/jrn1012/article/details/25781319
https://my.oschina.net/pangzhuzhu/blog/318012
總結(jié)
以上是生活随笔為你收集整理的使用session监听+spring MVC拦截器禁止用户重复登录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Jmeter教程 简单的压力测试
- 下一篇: 服务幂等以及常用实现方式