如何使用相同凭据login两次时使用户会话失效

我在RichFaces和Facelets中使用JSF 1.2。

我有许多会话范围的bean和一些应用程序bean的应用程序。

用户login,比方说,Firefox。 会话创buildID =“A”; 然后他打开Chrome并使用相同的凭据重新login。 会话创buildID =“B”。

当会话“B”被创build时,我希望能够销毁会话“A”。 怎么做?

也。 当Firefox中的用户做任何事情时,我希望能够显示一个popup窗口或某种通知,说“你已经注销,因为你已经从其他地方login”。

我有一个sessionListener跟踪创build和销毁的会话。 问题是,我可以将HTTPSession对象保存在应用程序范围的bean中,并在检测到用户已经login两次时将其销毁。 但有些事情告诉我,这是错误的,不会工作。

JSF是否跟踪服务器端某个地方的会话? 如何通过标识符访问它们? 如果没有,当用户login两次时如何退出用户的首次login?

与数据库无关的方法是让User有一个static Map<User, HttpSession>variables,并实现HttpSessionBindingListener (和Object#equals()Object#hashCode() )。 这样,你的web应用程序在一个不可预见的崩溃之后仍然可以正常工作,这可能会导致数据库值没有得到更新(当然,你可以创build一个ServletContextListener来重置webapp启动时的数据库,但这只是越来越多的工作)。

User应该是这样的:

 public class User implements HttpSessionBindingListener { // All logins. private static Map<User, HttpSession> logins = new ConcurrentHashMap<>(); // Normal properties. private Long id; private String username; // Etc.. Of course with public getters+setters. @Override public boolean equals(Object other) { return (other instanceof User) && (id != null) ? id.equals(((User) other).id) : (other == this); } @Override public int hashCode() { return (id != null) ? (this.getClass().hashCode() + id.hashCode()) : super.hashCode(); } @Override public void valueBound(HttpSessionBindingEvent event) { HttpSession session = logins.remove(this); if (session != null) { session.invalidate(); } logins.put(this, event.getSession()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { logins.remove(this); } } 

当你loginUser如下:

 User user = userDAO.find(username, password); if (user != null) { sessionMap.put("user", user); } else { // Show error. } 

那么它将调用valueBound() ,它将从logins映射中删除以前login的用户,并使会话无效。

如下注销User

 sessionMap.remove("user"); 

或者当会话超时时,将调用valueUnbound()方法,将用户从logins映射中移除。

  1. userLoggedInCount创build一个整数字段
  2. 在标记并将结果存储在会话中的每个login增量上。
  3. 在每个请求上检查数据库中的值和会话中的值,如果会话中的值小于数据库中的值,则使会话invalidate() ,并减小数据库中的值
  4. 每当会话被破坏时,也减less该值。

我喜欢用HttpSessionBindingListener从BalusC的答案。

但是,在Enterprise JavaBeansTM规范2.0版中,写有:

企业Bean不能使用读/写静态字段。 允许使用只读静态字段。 因此,build议将企业bean类中的所有静态字段声明为final

所以不是更好的做一个ApplicationScoped Bean存储表应用程序的广泛,而不使用静态字段?

它试了一下,似乎工作…

这是我的例子:

 @Named @ApplicationScoped public class UserSessionStorage implements java.io.Serializable,HttpSessionBindingListener { @Inject UserManagement userManagement; private static final long serialVersionUID = 1L; /** * Application wide storage of the logins */ private final Map<User, List<HttpSession>> logins = new HashMap<User, List<HttpSession>>(); @Override public void valueBound(final HttpSessionBindingEvent event) { System.out.println("valueBound"); /** * Get current user from userManagement... */ User currentUser = userManagement.getCurrentUser(); List<HttpSession> sessions = logins.get(currentUser); if (sessions != null) { for (HttpSession httpSession : sessions) { httpSession.setAttribute("invalid", "viewExpired"); } } else { sessions = new ArrayList<HttpSession>(); } HttpSession currentSession = event.getSession(); sessions.add(currentSession); logins.put(currentUser, sessions); } @Override public void valueUnbound(final HttpSessionBindingEvent event) { System.out.println("valueUnbound"); User currentUser = userManagement.getCurrentUser(); List<HttpSession> sessions = logins.get(currentUser); if (sessions != null) { sessions.remove(event.getSession()); } else { sessions = new ArrayList<HttpSession>(); } logins.put(currentUser, sessions); } 

}

– >对不起,我的英语…