SpringMVC實(shí)現(xiàn)賬號(hào)只能在一處登陸
一、問題引導(dǎo)
在Web開發(fā)中,實(shí)現(xiàn)一個(gè)賬號(hào)只能在一處登陸有兩種形式:1.當(dāng)某個(gè)賬號(hào)在某處登陸后,如果再在其他處登陸,將前一個(gè)賬號(hào)擠掉;2.當(dāng)某個(gè)賬號(hào)登陸后,此賬號(hào)在其他設(shè)備登陸提示已經(jīng)登陸,無法登陸。 正常的應(yīng)用邏輯第一種應(yīng)用較為廣泛,因此此篇文章討論一下第一種邏輯在spring mvc開發(fā)中一種較為簡單的實(shí)現(xiàn)方式。
然而在沒有長連接如WebSocket或者異步請(qǐng)求輪詢的情況下,我們之前登陸的賬號(hào)只能在下一次請(qǐng)求(同步或異步)才能獲取被擠掉的狀態(tài)(如頁面跳轉(zhuǎn))。
二、實(shí)現(xiàn)步驟
1.建立一個(gè)靜態(tài)Map,用來存放賬號(hào)和sessionID的對(duì)應(yīng)關(guān)系
2.在登陸時(shí),校驗(yàn)Map中是否已存在此賬號(hào),如果不存在說明是第一次登陸,將賬號(hào)和sessionID的對(duì)應(yīng)關(guān)系存放到靜態(tài)Map中;如果Map中存在此賬號(hào),并且sessionID和本次請(qǐng)求的sessionID不一致,將Map中的sessionID替換掉,因此之前登陸的賬戶在發(fā)送下一次非登錄和校驗(yàn)的請(qǐng)求會(huì)被攔截。
3.創(chuàng)建攔截器,攔截除登陸和校驗(yàn)url以外的所有請(qǐng)求。判斷請(qǐng)求的sessionID和靜態(tài)Map中此賬戶對(duì)應(yīng)的sessionID是否一致。如果不一致,跳轉(zhuǎn)到登陸頁面。
三、實(shí)現(xiàn)代碼
1.創(chuàng)建一個(gè)內(nèi)存數(shù)據(jù)類,用于存放靜態(tài)的數(shù)據(jù),并初始化:
public class MemoryData { private static Map<String, String> sessionIDMap = new HashMap<String,String>(); public static Map<String, String> getSessionIDMap() { return sessionIDMap; } public static void setSessionIDMap(Map<String, String> sessionIDMap) { MemoryData.sessionIDMap = sessionIDMap; } }
2.創(chuàng)建Controller,實(shí)現(xiàn)校驗(yàn)登陸用戶
@Controller public class AdminController extends BaseController{ @Autowired public AdminService adminService; /** * 校驗(yàn)登陸管理員 * @param request * @param response * @throws IOException */ @RequestMapping(value="/checkadmin") public void checkUserInfo(HttpServletRequest request,HttpServletResponse response) throws IOException{ //1在數(shù)據(jù)庫查找用戶 AdminBean admin = adminService.queryUserInfo(usernameS); //2將admin存放到Session中 request.getSession().setAttribute("admin", admin); //3在sessionIDMap中存放此用戶sessionID String sessionID = request.getRequestedSessionId(); String user = admin.getUsername(); if (!MemoryData.getSessionIDMap().containsKey(user)) { //不存在,首次登陸,放入Map MemoryData.getSessionIDMap().put(user, sessionID); }else if(MemoryData.getSessionIDMap().containsKey(user)&&!StringUtils.equals(sessionID, MemoryData.getSessionIDMap().get(user))){ MemoryData.getSessionIDMap().remove(user); MemoryData.getSessionIDMap().put(user, sessionID); } } }
3.創(chuàng)建攔截器
public class SingleUserInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { String url = request.getRequestURI(); //如果攔截到的是登錄的頁面的話放行 if(url.indexOf("login.do")>=0||url.indexOf("checkadmin.do")>=0){ return true; } //如果是其他請(qǐng)求地址,進(jìn)行攔截 AdminBean admin = (AdminBean) request.getSession().getAttribute("admin"); if(admin!=null){ String sessionid = MemoryData.getSessionIDMap().get(admin.getUsername()); //如果用戶名存在放心(即登錄放行) if(sessionid.equals(request.getSession().getId())){ return true; }else{ //如果請(qǐng)求的sessionID和此賬號(hào)Map中存放的sessionID不一致,跳轉(zhuǎn)到登陸頁 //判斷如果是異步請(qǐng)求,設(shè)置響應(yīng)頭 sessionstatus為timeout,自動(dòng)跳轉(zhuǎn),否則重定向 if(request.getHeader("x-requested-with")!=null && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){ response.setHeader("sessionstatus","timeout"); return false; }else{ String indexurl=request.getContextPath()+"/login.do"; response.sendRedirect(indexurl); return false; } } } //如果session中沒有admin,跳轉(zhuǎn)到登陸頁 request.getRequestDispatcher(request.getContextPath()+"/index.do").forward(request, response); return false; } }
4.在springmvc.xml配置文件中添加攔截器
<!--配置攔截器, 多個(gè)攔截器,順序執(zhí)行 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.jiefupay.newplat.controller.SingleUserInterceptor"/> </mvc:interceptor> </mvc:interceptors>
四、后續(xù)
此種方式實(shí)現(xiàn)一個(gè)賬號(hào)只能在一處登陸是一種較簡單的方法,當(dāng)然也可以通過移除session的方式實(shí)現(xiàn)。本文皆由本人親測實(shí)現(xiàn),如有錯(cuò)誤,歡迎指正。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- springmvc攔截器登錄驗(yàn)證示例
- SpringMVC攔截器——實(shí)現(xiàn)登錄驗(yàn)證攔截器的示例代碼
- 詳解springmvc攔截器攔截靜態(tài)資源
- SpringMVC 攔截器不攔截靜態(tài)資源的三種處理方式方法
- 詳解利用SpringMVC攔截器控制Controller返回值
- 淺談springMVC攔截器和過濾器總結(jié)
- 詳解SpringMVC中使用Interceptor攔截器
- 詳解SpringMVC攔截器(資源和權(quán)限管理)
- SpringMVC攔截器實(shí)現(xiàn)登錄認(rèn)證
- Spring MVC--攔截器實(shí)現(xiàn)和用戶登陸例子
相關(guān)文章
SpringBoot中各個(gè)層級(jí)結(jié)構(gòu)的具體實(shí)現(xiàn)
在SpringBoot項(xiàng)目中,常常會(huì)把代碼文件放入不同的包中,本文主要介紹了SpringBoot中各個(gè)層級(jí)結(jié)構(gòu)的具體實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05Java基于面向?qū)ο髮?shí)現(xiàn)一個(gè)戰(zhàn)士小游戲
這篇文章主要為大家詳細(xì)介紹了Java如何基于面向?qū)ο髮?shí)現(xiàn)一個(gè)戰(zhàn)士小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-07-07MyBatis 中 ${}和 #{}的正確使用方法(千萬不要亂用)
這篇文章主要介紹了MyBatis 中 ${}和 #{}的正確使用方法,本文給大家提到了MyBatis 中 ${}和 #{}的區(qū)別,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07JAVA使用爬蟲抓取網(wǎng)站網(wǎng)頁內(nèi)容的方法
這篇文章主要介紹了JAVA使用爬蟲抓取網(wǎng)站網(wǎng)頁內(nèi)容的方法,實(shí)例分析了java爬蟲的兩種實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07