1. 程式人生 > >java web 使用者單點登入的方案的基本實現

java web 使用者單點登入的方案的基本實現

      在實驗室剛剛結束的專案中,有這樣一個需求,一個賬號同時只能在一個地方登入,如果在其他地方登入則提示已在別處登入,直到已登入賬號失效或退出,同時,同一瀏覽器同時只能登入一個使用者。

      首先,考慮不能重複登入的問題。在專案中,我使用session來儲存使用者的資訊,使用者登入時,建立一個session,將使用者名稱,使用者邏輯Id,登入時間等屬性存放到該session中。考慮使用Application來實現禁止重複登入。定義一個Map<Long,String>型別的變數loginUserMap。其每條記錄儲存登入使用者的邏輯Id和對應session的sessionId。這樣,每次使用者登入的時候遍歷loginUserMap,如果沒有對應的userlogicId或sessionId則允許登入,否則提示已在別處登入。

					// 判斷是否重複登入
					isloginexists = false;
					ifsessioninvalidate = false;
					loginUserMap = (Map<Long, String>) acx.getApplication().get(WebConstant.LOGIN_USER_MAP);
					if (loginUserMap == null) {
						loginUserMap = new HashMap<Long, String>();
					}
					HttpServletRequest request = ServletActionContext.getRequest();
					String sessionId = request.getSession(false).getId();
					System.out.println("sessionId" + sessionId);
					for (Long userlogicId2 : loginUserMap.keySet()) {
						if (!userlogicId2.equals(userlogicId) && !loginUserMap.containsValue(sessionId)) { // 不同瀏覽器不允許相同使用者重複登入
							continue;
						}
						
						if(userlogicId2.equals(userlogicId)&&!loginUserMap.containsValue(sessionId)){
							setIfsessioninvalidate(true);
						}
						isloginexists = true;
						break;
					}
					if (isloginexists) {
						setTip("loginexists");
						if(ifsessioninvalidate==true){
							request.getSession(false).invalidate();
					}
			
					} else {
					
						loginUserMap.put(userlogicId, sessionId);
						acx.getApplication().put(WebConstant.LOGIN_USER_MAP,loginUserMap);
						acx.getSession().put(WebConstant.USER_ID, getUsername());
						acx.getSession().put(WebConstant.USER_LOGICID,userManageService.findbyUsername(getUsername()).getLogicId());
						acx.getSession().put(WebConstant.LOGIN_TIME, new Date());
					       }


在使用者退出的操作中,將loginUserMap中對應的使用者logicId和sessionId清除,同時清除session中的使用者資訊。

		   Map<Long, String> loginUserMap = (Map<Long, String>)acx.getApplication().get(WebConstant.LOGIN_USER_MAP);
		   String username=userManageService.findByLogicId(userlogicId).getUserName();
		   if(loginUserMap.containsKey(userlogicId)){
			   loginUserMap.remove(userlogicId);	
		   }
		   session.getServletContext().setAttribute("loginUserMap", loginUserMap);
	    
		   Long id=(Long) session.getAttribute(WebConstant.USER_LOGICID);
		   if(id!=null)
			this.userManageService.userLogout(id);
		   
		   session.removeAttribute(WebConstant.USER_ID);
		   session.removeAttribute(WebConstant.USER_LOGICID);
		   session.removeAttribute(WebConstant.LOGIN_TIME);
		
		   //使Session失效
		   session.invalidate();
		
		   response.setHeader("Cache-Control","no-cache");
		   response.setHeader("Cache-Control","no-store");
		   response.setDateHeader("Expires", 0);
		   
    在session失效的監聽器處理中,也做相同的操作,保證登入session超時時從loginUserMap中刪除該使用者,以保證後繼賬號能夠正常登入。
   
public class SessionListener implements HttpSessionListener{
	 
	@Override
	public void sessionCreated(HttpSessionEvent event) {
		 
	}

	
	@Override
	public void sessionDestroyed(HttpSessionEvent event) {
		//監聽session的失效和銷燬
		HttpSession session=event.getSession();
		ServletContext application=session.getServletContext();
	
		try{
			 String username=(String) session.getAttribute(WebConstant.USER_ID);
			 Long userlogicId=(Long)session.getAttribute(WebConstant.USER_LOGICID);
			 Map<Long, String> loginUserMap = (Map<Long, String>)application.getAttribute(WebConstant.LOGIN_USER_MAP); 
			 if(loginUserMap.containsKey(userlogicId))
				 loginUserMap.remove(userlogicId);
			 application.setAttribute(WebConstant.LOGIN_USER_MAP, loginUserMap);
			  System.out.println("session:"+session.getId()+"已失效");
		 }
		 catch(Exception e){
			 	System.out.println(e.getMessage());
		 }
	}


}
     到這裡,基本能做到限制使用者的重複登入了,但是靠這些異常情況依然無法處理,如使用者使用過程中關閉瀏覽器,再次登入時,由於資訊記錄在伺服器端的application中且未按照正常安全退出流程執行,則執行登入操作會提示"已在別處登入"。要解決這個問題,參考博文《java web使用者單點登入異常情況處理之使用者的非正常退出》。