我正在使用不允許併發登錄(同一用戶和通行證)的Java EE 6(JSF CDI EJB)的Web應用程序。Java EE 6併發會話和共享
我喜歡的是:
如果需要兩次第一屆用戶登錄到無效和舊的會話數據(包括與SessionScope或Apache的CODI其他領域一樣WindowScope所有CDI豆)被轉移到新的會議。
這有點像通緝會話劫持的做法:-)
我正在使用不允許併發登錄(同一用戶和通行證)的Java EE 6(JSF CDI EJB)的Web應用程序。Java EE 6併發會話和共享
我喜歡的是:
如果需要兩次第一屆用戶登錄到無效和舊的會話數據(包括與SessionScope或Apache的CODI其他領域一樣WindowScope所有CDI豆)被轉移到新的會議。
這有點像通緝會話劫持的做法:-)
我解決了這個問題帶有過濾器的幫助下
公共類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。通過將它們更改回原點,一切正常。
事情,我需要補充:
在此評論失蹤人員:
問候
我希望看到你回覆的任何人都會意識到這只是一個瘋狂的內存泄漏(HttpSessions映射永遠不會被清除)。 – 2015-03-10 23:39:52
你說得對。此處缺少觀察sessionDestroyed事件的HttpSessionListener。偵聽器從地圖中刪除所有無效的會話(即超時,註銷,...) – urbiwanus 2015-03-11 07:25:57
有是Java EE 6
對此沒有內在的機制,我無法想象,你要像一個持續的東西轉移從一個會話到另一個會話的用例(例如一個開放的結賬過程),我建議你只需要跟蹤用戶的GUI狀態即。
RESTful URL聽起來像是一個理想的方法。堅持最後一次用戶URL /用戶操作(例如www.myapp.com/orders/new/12
),並重新打開新登錄。
如果你不想在數據庫中保存它,應用程序範圍的映射userid/url可能是KISS的方式。
你可以使用一個無狀態的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.)
}
爲什麼不您只隱藏已登錄用戶的登錄頁面,並拒絕任何使用類似*的消息進行的登錄嘗試。如果您希望登錄,請登出ogin作爲一個不同的用戶。「*或者像這樣明智的東西。 – BalusC 2012-07-16 21:16:11
它並不那麼簡單。因爲用戶希望在不關心登錄的情況下在兩個不同的工作站上工作。他只是想看到相同的輸出和應用程序的相同狀態 – urbiwanus 2012-07-16 21:29:38
那麼爲什麼你需要使第一次會話無效? – BalusC 2012-07-16 21:52:48