0

设想:

用户使用 Firefox 登录 website.com。登录凭据有效,用户被定向到会员页面。

用户尝试使用 chrome 登录 website.com。登录凭据有效,因为用户已经使用 firefox 登录,系统会抛出错误,要求用户关闭其他会话以通过 chrome 登录。

我怎样才能检测到呢?现在,如果用户只使用一个浏览器,我能够检测到它,但是当用户使用两种不同的浏览器在不同时间登录时似乎会中断。

编辑* 我想说这不仅仅是使用不同的浏览器,该网站不应允许多人使用相同的登录凭据登录。

4

4 回答 4

3

我假设您的应用程序是基于 j2EE/servlet 的。如果是这种情况,两个浏览器是相互独立的,因此它们有自己的 sessionId 并且可以独立运行,只要您的应用程序不干扰。

为了防止这种情况,一种实现方法是,在您的 servlet 中保留 SessionID 和 UserID 的 hashmap。您在每次成功登录时填充此信息,例如通过过滤器或阀门。当您填充哈希图时,请检查是否有任何其他 sessionID 已在使用此用户 ID。如果使用,请检查对应的 sessionID 是否仍然处于活动状态。如果它未激活,则允许登录,并删除陈旧的 sessionID。如果它处于活动状态,则终止另一个会话并允许登录。

于 2012-07-20T18:24:41.267 回答
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.");
}
于 2012-07-20T18:09:44.243 回答
1

如果您使用的是 Spring Security - 它可以由配置文件中的参数指定。

如果只是普通的 java - 在登录期间将用户的会话 ID 放入一些存储中;当他再次尝试登录时,您应该禁止它。但是您需要避免用户在关闭浏览器后很长时间处于存储状态的情况(一种可能的解决方案是短会话超时 + 保持活动请求)

于 2012-07-20T18:11:39.373 回答
1

您可以将登录用户的映射存储在应用程序范围变量(如 ServletContext)上。例如,在您的身份验证 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。您仍然需要考虑地图操作本身(例如使用 jucConcurrentHashMap 可能吗?)。

当用户注销或会话超时时,您还必须注意清理(例如从地图中删除)。

您还必须考虑到用户可能会通过这种方法将自己锁定很长时间(例如关闭浏览器但未正确注销,会话需要在映射被清除之前超时)。

编辑:您还需要考虑可伸缩性,这取决于您的应用程序。你期待一百万在线用户吗?还是只有几千?

于 2012-07-20T18:36:37.903 回答