java web 使用者單點登入的方案的基本實現
阿新 • • 發佈:2019-01-06
在實驗室剛剛結束的專案中,有這樣一個需求,一個賬號同時只能在一個地方登入,如果在其他地方登入則提示已在別處登入,直到已登入賬號失效或退出,同時,同一瀏覽器同時只能登入一個使用者。
首先,考慮不能重複登入的問題。在專案中,我使用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中的使用者資訊。
在session失效的監聽器處理中,也做相同的操作,保證登入session超時時從loginUserMap中刪除該使用者,以保證後繼賬號能夠正常登入。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);
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使用者單點登入異常情況處理之使用者的非正常退出》。