SpringMVC實現賬號只能在一處登陸
阿新 • • 發佈:2019-01-03
一、問題引導
在Web開發中,實現一個賬號只能在一處登陸有兩種形式:
- 1.當某個賬號在某處登陸後,如果再在其他處登陸,將前一個賬號擠掉;
- 2.當某個賬號登陸後,此賬號在其他裝置登陸提示已經登陸,無法登陸。
正常的應用邏輯第一種應用較為廣泛,因此此篇文章討論一下第一種邏輯在spring mvc開發中一種較為簡單的實現方式。然而在沒有長連線如WebSocket或者非同步請求輪詢的情況下,我們之前登陸的賬號只能在下一次請求(同步或非同步)才能獲取被擠掉的狀態(如頁面跳轉)。
二、實現步驟
- 1.建立一個靜態Map,用來存放賬號和sessionID的對應關係
- 2.在登陸時,校驗Map中是否已存在此賬號,如果不存在說明是第一次登陸,將賬號和sessionID的對應關係存放到靜態Map中;如果Map中存在此賬號,並且sessionID和本次請求的sessionID不一致,將Map中的sessionID替換掉,因此之前登陸的賬戶在傳送下一次非登入和校驗的請求會被攔截。
- 3.建立攔截器,攔截除登陸和校驗url以外的所有請求。判斷請求的sessionID和靜態Map中此賬戶對應的sessionID是否一致。如果不一致,跳轉到登陸頁面。
三、實現程式碼
- 1.建立一個記憶體資料類,用於存放靜態的資料,並初始化:
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.建立Controller,實現校驗登陸使用者
@Controller
public class AdminController extends BaseController{
@Autowired
public AdminService adminService;
/**
* 校驗登陸管理員
* @param request
* @param response
* @throws IOException
*/
@RequestMapping(value="/checkadmin")
public void checkUserInfo(HttpServletRequest request,HttpServletResponse response) throws IOException{
//1在資料庫查詢使用者
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.建立攔截器
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;
}
//如果是其他請求地址,進行攔截
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{ //如果請求的sessionID和此賬號Map中存放的sessionID不一致,跳轉到登陸頁
//判斷如果是非同步請求,設定響應頭 sessionstatus為timeout,自動跳轉,否則重定向
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,跳轉到登陸頁
request.getRequestDispatcher(request.getContextPath()+"/index.do").forward(request, response);
return false;
}
}
- 4.在springmvc.xml配置檔案中新增攔截器
<!--配置攔截器, 多個攔截器,順序執行 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.jiefupay.newplat.controller.SingleUserInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>