情景:
用户使用firefox登录website.com。登录凭证有效,用户将被定向到会员页面。
用户尝试使用chrome登录website.com。登录凭据有效,因为使用已经使用firefox登录,系统将抛出错误,要求用户关闭其他会话以通过chrome登录。
我该如何检测?现在,如果用户只使用一个浏览器,我可以检测到它,但是当用户使用两个不同的浏览器在不同时间登录时,它似乎会中断。
编辑*我想说这不仅仅是使用不同的浏览器,网站不应该允许多人使用相同的登录凭据登录。
答案 0 :(得分:3)
我假设您的应用程序是基于j2EE / servlet的。如果是这种情况,两个浏览器彼此独立,因此它们有自己的sessionId并且可以独立运行,只要您的应用程序不会干扰。
要防止出现这种情况,实现的一种方法是在servlet中保留SessionID和UserID的哈希映射。您可以在每次成功登录时填充此信息,例如通过过滤器或阀门。在填充哈希映射时,请进行检查,以查看是否有任何其他sessionID已在使用此userID。如果使用它,请检查相应的sessionID是否仍处于活动状态。如果它不活动,请允许登录,并删除陈旧的sessionID。如果它处于活动状态,则终止其他会话并允许登录。
答案 1 :(得分:1)
在您的应用程序中,保持每次调用应用程序后更新的用户超时。您可以将用户定义为“锁定”到会话中(例如您的firefox会话),直到超时到期或用户请求注销。当您登录其他浏览(例如,chrome)时,它会检查是否存在活动会话,如果存在,则拒绝登录尝试。
我打算做一个简单的例子。这甚至不接近生产准备,仅用于说明目的。
class User {
long lastCheckin;
int userId;
String username;
}
现在,当有人在应用中执行任何操作时,例如查看页面,就可以执行此操作
user.lastCheckin = System.currentTimeMillis();
现在,当某人专门请求注销时,您可以执行此操作
user.lastCheckin = 0L;
现在,当有人试图登录时,你会这样做
if(user.lastCheckin + PREDEFINED_TIMEOUT > System.currentTimeMillis()) {
return new LoginResponse(false,"User is active in another session.");
}
答案 2 :(得分:1)
如果您使用的是Spring Security,则可以通过配置文件中的参数指定。
如果只是简单的java - 在登录期间将用户的会话ID放到某个存储中;当他再次尝试登录时,你应该禁止它。 但是,当用户在关闭浏览器后很长时间处于存储状态时,您需要避免出现这种情况(一种可能的解决方案是短会话超时+保持活动请求)
答案 3 :(得分:1)
您可以在应用程序范围变量(如ServletContext)上存储已登录用户的映射。例如,在您的auth servlet上,您可以执行以下操作:
Map<String,String> activeUsers = request.getSession().getServletContext().getAttribute("__ONLINE_AUTHENTICATED_USERS");
//if null, context hasn't been prepared yet, create and attach a new one?2
但你必须要小心。作为应用程序范围变量,您需要确保一些线程安全性,这是servletContext.setAttribute / getAttribute提供的内容(例如,那些操作不是线程安全的)。您可以通过使用某种应用程序生命周期监听器来“初始化”servletContext以使用户映射来处理此问题。这样您就不必担心set / getAttribute。你还需要考虑地图操作本身(例如,使用j.u.c.ConcurrentHashMap吗?)。
当用户退出或会话超时时,您还必须注意清理(例如从地图中删除)。
您还必须考虑用户可能会通过这种方法将自己锁定很长时间(例如,关闭浏览器但不正确注销,会话需要在映射清除之前超时)。
编辑: 您还需要考虑可伸缩性,这取决于您的应用程序。您期待一百万在线用户吗?或者只有几万个?