Java 当用户使用相同的凭据登录两次时,如何使用户会话无效
我将JSF1.2与Richfaces和Facelets一起使用 我有一个包含许多会话范围bean和一些应用程序bean的应用程序 用户使用Firefox登录。使用ID=“A”创建会话; 然后,他打开Chrome并使用相同的凭据再次登录。使用ID=“B”创建会话 创建会话“B”时,我希望能够销毁会话“A”。怎么做 还有。当Firefox中的用户执行任何操作时,我希望能够显示一个弹出窗口或某种通知,说明“您已注销,因为您已从其他地方登录” 我有一个sessionListener,他跟踪创建和销毁的会话。问题是,我可以将HTTPSession对象保存在应用程序范围的bean中,并在检测到用户已登录两次时销毁它。但有些事情告诉我,这是错误的,是行不通的 JSF是否在服务器端某处跟踪会话?如何通过标识符访问它们?如果没有,当用户登录两次时,如何取消其第一次登录Java 当用户使用相同的凭据登录两次时,如何使用户会话无效,java,session,jsf,richfaces,facelets,Java,Session,Jsf,Richfaces,Facelets,我将JSF1.2与Richfaces和Facelets一起使用 我有一个包含许多会话范围bean和一些应用程序bean的应用程序 用户使用Firefox登录。使用ID=“A”创建会话; 然后,他打开Chrome并使用相同的凭据再次登录。使用ID=“B”创建会话 创建会话“B”时,我希望能够销毁会话“A”。怎么做 还有。当Firefox中的用户执行任何操作时,我希望能够显示一个弹出窗口或某种通知,说明“您已注销,因为您已从其他地方登录” 我有一个sessionListener,他跟踪创建和销毁的会
userLoggedInCount
invalidate()
会话并减小数据库中的值独立于数据库的方法是让
用户
拥有一个静态映射
变量并实现(和)。这样,您的webapp在发生意外崩溃后仍能正常工作,这可能会导致DB值无法更新(当然,您可以创建一个ServletContextListener
,在webapp启动时重置DB,但这只是越来越多的工作)
以下是用户
的外观:
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);
}
}
然后它将调用valueBound()
,这将从logins
映射中删除任何以前登录的用户,并使会话无效
当您按如下方式注销用户时:
User user = userDAO.find(username, password);
if (user != null) {
sessionMap.put("user", user);
} else {
// Show error.
}
sessionMap.remove("user");
或者,当会话超时时,将调用valueUnbound()
,从而将用户从登录图中删除。我喜欢使用HttpSessionBindingListener的BalusC给出的答案
但在Enterprise JavaBeansTM规范2.0版中,有这样一条规定:
企业Bean不能使用读/写静态字段。使用只读静态字段是非常困难的
允许。因此,建议企业bean类中的所有静态字段
宣布为最终决定
所以,制作一个应用程序范围的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);
}
@Named
@适用范围
公共类UserSessionStorage实现java.io.Serializable、HttpSessionBindingListener{
@注入
用户管理用户管理;
私有静态最终长serialVersionUID=1L;
/**
*登录的应用程序范围存储
*/
private final Map logins=new HashMap();
@凌驾
public void valueBound(最终HttpSessionBindingEvent事件){
System.out.println(“valueBound”);
/**
*从userManagement获取当前用户。。。
*/
User currentUser=userManagement.getCurrentUser();
列表会话=logins.get(currentUser);
如果(会话!=null){
用于(HttpSession HttpSession:会话){
httpSession.setAttribute(“无效”、“视图过期”);
}
}否则{
sessions=newarraylist();
}
HttpSession currentSession=event.getSession();
sessions.add(当前会话);
logins.put(当前用户、会话);
}
@凌驾
public void valueUnbound(最终HttpSessionBindingEvent事件){
System.out.println(“valueUnbound”);
User currentUser=userManagement.getCurrentUser();
列表会话=logins.get(currentUser);
如果(会话!=null){
移除(event.getSession());
}否则{
sessions=newarraylist();
}
logins.put(当前用户、会话);
}
}
->对不起,我的英语…我想我可以使用应用程序范围的类来代替DB。例如,问题是如何从阶段侦听器访问它?好的解决方案。你可以通过FacesContext获取外部上下文。这个算法可能不够。这一理论是完美的,但在实践中,如果浏览器将会话保存在cookie中并从中还原回来,它将不起作用。请看步骤2。如我所说,如果浏览自动恢复会话,它将不会通过任何LoginHandler或LoginMethod或任何可控位置来执行该标志的增量。在这种情况下如何行动?谢谢你的回答。我猜“sessionMap.put(“user”,user);”应该是“sessionMap.put(username,user);”。否则,如果具有不同凭据的不同用户登录,我们会将第一个用户踢出。这是不正常的。您不希望在一个客户端会话期间有不同的登录用户。另外,不要将会话映射与应用程序映射混淆。好的,我现在知道sessionMap是ExternalContext.sessionMap。它可以工作:)。当调用valueUnbound()
时,您不想使会话失效吗?@Harry:不,甚至,实际上是无效本身导致了方法被调用:)HttpSessionBindingListener不是EJB。只有那些带有javax.ejb.*
主注释的类,例如@Stateless
才是ejb。