如何使用相同凭据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
映射中移除。
- 在
userLoggedInCount
创build一个整数字段 - 在标记并将结果存储在会话中的每个login增量上。
- 在每个请求上检查数据库中的值和会话中的值,如果会话中的值小于数据库中的值,则使会话
invalidate()
,并减小数据库中的值 - 每当会话被破坏时,也减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); }
}
– >对不起,我的英语…