2012-07-16 108 views
2

我正在使用不允許併發登錄(同一用戶和通行證)的Java EE 6(JSF CDI EJB)的Web應用程序。Java EE 6併發會話和共享

我喜歡的是:

如果需要兩次第一屆用戶登錄到無效和舊的會話數據(包括與SessionScope或Apache的CODI其他領域一樣WindowScope所有CDI豆)被轉移到新的會議。

這有點像通緝會話劫持的做法:-)

+0

爲什麼不您只隱藏已登錄用戶的登錄頁面,並拒絕任何使用類似*的消息進行的登錄嘗試。如果您希望登錄,請登出ogin作爲一個不同的用戶。「*或者像這樣明智的東西。 – BalusC 2012-07-16 21:16:11

+0

它並不那麼簡單。因爲用戶希望在不關心登錄的情況下在兩個不同的工作站上工作。他只是想看到相同的輸出和應用程序的相同狀態 – urbiwanus 2012-07-16 21:29:38

+0

那麼爲什麼你需要使第一次會話無效? – BalusC 2012-07-16 21:52:48

回答

0

我解決了這個問題帶有過濾器的幫助下

公共類SessionReplicationFilter實現過濾器{

@Inject 
SessionReplicationManager manager; 

public SessionReplicationFilter() { 
} 


@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
    //Process chain first 
    if (chain != null) { 
     chain.doFilter(request, response); 
    } 

    //check http request 
    if (request instanceof HttpServletRequest) { 
     HttpServletRequest httpRequest = (HttpServletRequest) request; 
     // Retrieve the session and the principal (authenticated user) 
     // The principal name is actually the username 
     HttpSession session = httpRequest.getSession(); 
     Principal principal = httpRequest.getUserPrincipal(); 
     if (principal != null && principal.getName() != null && session != null) { 
      manager.checkExistingSession(principal.getName(), session)) 
     } 
    } 

} 

@Override 
public void init(FilterConfig filterConfig) throws ServletException { 

} 

@Override 
public void destroy() { 

} 

}

經理看上去很以下

@ApplicationScoped 公共類SessionReplicationManager {

private Map<String, HttpSession> map = new ConcurrentHashMap<String, HttpSession>(); 


public boolean checkExistingSession(String user, HttpSession session) { 
    if (map.keySet().contains(user)) { 
     if (!session.getId().equals(map.get(user).getId())) { 
      System.out.println("User already logged in "); 
      HttpSession oldSession = map.get(user); 
      // copies all attributes from the old session to the new session (replicate the session) 
      Enumeration<String> enumeration = oldSession.getAttributeNames(); 
      while (enumeration.hasMoreElements()) { 
       String name = enumeration.nextElement(); 
       System.out.println("Chaning attribut " + name); 
       session.setAttribute(name, oldSession.getAttribute(name)); 
      } 
      // invalidates the old user session (this keeps one session per user) 
      oldSession.invalidate(); 
      map.put(user, session); 
      return true; 
     } 
    } else { 
     System.out.println("Putting "+user+" into session cache"); 
     map.put(user, session); 
     return false; 
    } 
    return false; 
} 

}

它工作得很好CODI ViewScoped註釋豆類

如果第一個你(AJAX)請求會導致會話失效異常,即使使用恢復會話按鈕也可輕鬆處理該異常

只有viewcoped bean的一個小問題是,它們會得到新的視圖ID。通過將它們更改回原點,一切正常。

事情,我需要補充:

  • 自動註銷(AJAX輪詢的WebSockets,...)
  • 某種類型的註冊表的所有viewscoped-ID存儲

在此評論失蹤人員:

  • web.xml配置

問候

+0

我希望看到你回覆的任何人都會意識到這只是一個瘋狂的內存泄漏(HttpSessions映射永遠不會被清除)。 – 2015-03-10 23:39:52

+0

你說得對。此處缺少觀察sessionDestroyed事件的HttpSessionListener。偵聽器從地圖中刪除所有無效的會話(即超時,註銷,...) – urbiwanus 2015-03-11 07:25:57

0

有是Java EE 6

對此沒有內在的機制,我無法想象,你要像一個持續的東西轉移從一個會話到另一個會話的用例(例如一個開放的結賬過程),我建議你只需要跟蹤用戶的GUI狀態即

RESTful URL聽起來像是一個理想的方法。堅持最後一次用戶URL /用戶操作(例如www.myapp.com/orders/new/12),並重新打開新登錄。

如果你不想在數據庫中保存它,應用程序範圍的映射userid/url可能是KISS的方式。

+0

我不確定這是否適用於我所有的用例。但我會嘗試。 – urbiwanus 2012-07-17 08:20:27

+0

出於好奇 - 你正在建造什麼樣的系統?爲什麼用戶在相對較短的時間內登錄到不同的站點? – 2012-07-17 10:48:19

+0

想象一下像不同終端的POS系統。我無法詳談。我很抱歉 – urbiwanus 2012-07-17 18:07:10

0

你可以使用一個無狀態的bean的用戶,所以每一次應該嘗試登錄/重新登錄,當前會話被無效(在日誌中程序的開始)

考慮這個那種方法:

try {   
    session = request.getSession(); //the request is passed by another page or action 
    if(session.getAttribute("user") != null) { 

      //your code to forward or handle the existing user (re-log in/ do nothing etc.) 
}