1. 程式人生 > >SpringMVC實現賬號只能在一處登陸

SpringMVC實現賬號只能在一處登陸

一、問題引導

在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>

原文