在asp.net网站中如何防止同一用户ID的多次登录?

时间:2010-04-08 10:35:11

标签: c# asp.net

请指导如何使用用户ID一次防止多个用户登录?

我搜索了互联网并找到了一些方法,但不知怎的,他们在这些情况下不起作用:

  1. 如果关闭浏览器中的javascript。
  2. 如果用户没有点击退出并直接关闭浏览器。
  3. 请以某种方式建议我。

    感谢

    haansi

8 个答案:

答案 0 :(得分:18)

我们按照以下方针为此实施了一个系统:

  • 向用户个人资料添加了一个属性以保存其会话ID。
  • 每当用户登录时,将其会话ID存储在配置文件中。
  • 在需要此级别安全性的任何页面上,检查配置文件中存储的会话ID是否与其会话匹配。此检查可以在自定义AuthorizeRequest事件处理程序中执行,也可以在这些页面派生自的Base类中执行,如果不是,则将它们重定向到登录页面。

我们选择了基类选项,因为我们有两个级别的身份验证:

  1. 用户有一个cookie令牌,以证明他们已经在过去的某个时间点登录 - 这对于向他们显示受限制的网站内容很好。
  2. 用户实际上已在此会话中提供了他们的登录详细信息 - 在向他们显示任何个人详细信息(电子邮件地址,偏好设置,已保存的职位搜索等)时,这是必需的。
  3. 几乎所有系统都会找到主要问题:

    1. 使用用户的IP地址是不可靠的 - 企业用户,代理人后面的人等经常共享一个IP地址,因此会“显示”为同一个用户。
    2. 依赖用户注销是不可靠的 - 用户计算机/浏览器可能崩溃而没有给他们注销的机会,用户可能/将忘记注销。
    3. 依赖会话超时是不可靠的 - 如果您没有使用InProc个会话,则SessionEnd事件永远不会触发,如果您的服务器崩溃,则不会调用该事件等。
    4. 您可以通过我的解决方案找到的问题是:

      1. 它不会阻止第二个用户登录 - 而是会锁定第一个用户,这应该首先阻止共享细节。
      2. 如果您没有将其作为AuthorizeRequest处理程序实现,则必须记住对应该锁定的页面执行检查。
      3. 回复评论

        回应您的具体问题:

        1. default Profile Provider将数据存储在与成员资格提供程序相同的SQL数据库中(这些表与成员资格和角色表一起创建)。如果你要将它“存储在缓存中”,则需要成为全局应用程序缓存,沿着KMan suggests in option 2行 - 并且如指出注释,你需要为此构建一个超时,这导致了可靠地确定这个问题。
        2. 用户未注销:这是在我们的系统中通过不锁定 future 用户来处理,而是通过锁定以前登录的用户 - 所以:
          • Alice来到该网站,登录,开始浏览。
          • Bob来到该网站,并使用Alice的详细信息登录,开始浏览。
          • Alice试图继续浏览,被锁定,必须再次登录。
          • 鲍勃现在被锁定了。
        3. 最基本的,这不会阻止用户共享他们的登录,但会导致他们烦恼,迫使他们继续登录。如果需要,可以为登录过程添加延迟 - 所以如果不同会话ID尝试在会话超时(默认为20分钟)或其他时间(例如,基于用户在页面上花费的平均时间)登录站点,然后拒绝登录尝试。

答案 1 :(得分:11)

可能有几种可能性。快速回复是:

  1. 在数据库中维护一个标志;每次登录/退出时都会更新标志。例如,如果标志已经为真,则每次认证请求都可以拒绝登录请求。

  2. 或者,您可以在Application对象中维护用户列表,并使用.Contains查看它是否已存在。

  3. <强> - 编辑 -

    让我们尝试数据库标志选项;并假设您有一个名为StillLoggedIn(User)的方法来更新日期/时间和标记。

    因此,当用户登录时:

    1. 该应用将验证用户并设置flag = 1,并标记日期/时间戳。
    2. 对于后续请求,应用会调用StillLoggedIn(User);

    3. 准备一个可以不时浏览数据库的Windows服务(如果你有10000个用户,可以说5分钟后)。如果 currentTime减去lastUsedTime大于,比如5分钟,该服务会将数据库日期/时间与当前日期/时间进行比较,并将标记标记为0

    4. 它可以是数据库和Windows服务之外的任何东西。

答案 2 :(得分:2)

这就是我的方式。

用户登录后,检查来自DB的flag和sessionID,如果发现使用相同的帐户和不同的sessionID登录(比较新生成的当前sessionID和来自DB的sessionID),请提醒用户“系统检测到您没有从您上次登录时,点击&lt;“确定”&gt;退出上次登录并创建新会话。“ 如果没问题,只需将旧的SessionId替换为DB中的当前SessionID。

还有一件事是在每个页面中检查来自DB的当前sessionID和sessionID,如果不相同,则注销并重定向到登录页面。

无论用户没有正确注销或只是关闭浏览器,用户都有机会退出自己,无需等到IIS会话结束。 它将阻止同时使用同一帐户进行多次登录。

希望这有帮助,谢谢...

答案 3 :(得分:2)

我们所做的是使用会话状态和应用程序状态的组合来防止重复登录。

当用户登录时,他从user.net数据库中检索到userId,并将其作为唯一对象保存在Application状态中。

由于应用程序状态对应用程序是全局的而不是特定于用户会话,因此我们可以检查userId是否已保存在应用程序状态中。如果已经保存,我们可以通知用户并停止登录。 当会话到期时(在Global.asax文件中的Session_End上),可以从Application状态中删除该特定用户的Application状态对象,以便他可以在会话过期后再次登录。

这是代码: 在Login.aspx.cs中:

protected void OnLoggingIn(object sender, LoginCancelEventArgs e)
    {
        // Accesses the database to get the logged-in user.
        MembershipUser userInfo = Membership.GetUser(LoginUser.UserName);
        UserMan.UserID = userInfo.ProviderUserKey.ToString();

        if (Application[UserMan.UserID] != null)
        {
            if (Convert.ToString(Application[UserMan.UserID]) == UserMan.UserID)
            {
                e.Cancel = true;
            }
            else
            {
                // Save the user id retrieved from membership database to application state.
                Application[UserMan.UserID] = UserMan.UserID;
            }
        }
        else
        {
            Application[UserMan.UserID] = UserMan.UserID;                
        }
    }

在Global.asax中:

void Session_End(object sender, EventArgs e)
    {
        // Code that runs when a session ends. 
        // Note: The Session_End event is raised only when the sessionstate mode
        // is set to InProc in the Web.config file. If session mode is set to StateServer 
        // or SQLServer, the event is not raised.

        if (Application[UserMan.UserID] != null)
        {
            if (Convert.ToString(Application[UserMan.UserID]) == UserMan.UserID)
            {                    
                Application.Contents.Remove(UserMan.UserID);
            }
        }
    }

虽然这个解决方案看起来有点乱,但是如果没有太多的编码和更少的数据库命中,它的效果会非常好。

答案 4 :(得分:1)

这里没有一个答案,因为它取决于您如何验证用户。但是,基本逻辑很简单 - 当用户登录时,根据已登录用户的列表检查其用户名或ID,如果匹配,则不对其进行身份验证(而是给他们某种消息解释)为什么他们无法登录)。

显然,您执行此操作的确切方式取决于您对用户进行身份验证以及存储用户详细信息的方式 - 如果您需要更多帮助,则需要提供更多详细信息。

答案 5 :(得分:1)

我查看了成员资格表并没有看到像“IsLoggedIn”这样的列,因此会员资格API不符合此要求。

可能是您可以使用Asp.net Cache系统并将用户标记为“LoggedIn”。通过这种方式,您可以检查额外的登录信息。

答案 6 :(得分:0)

Zhaph - Ben Duguid,Little note配置文件无法在AuthenticateRequest中访问,因为它不会在AcquireSessionState应用程序事件之前创建,所以如果他们使用这种方法(而不是页面方法)他们必须处理AcquireRequestState或PostAcquireRequestState < / p>

答案 7 :(得分:0)

当成员进入时。设置一个Random int ex。 randNo,保存缓存[UserName] = randNo,session [UserName] = randNo。 当成员访问我们检查的任何页面时:cache [UserName] == Session [UserName]没问题,否则该用户将登出。 (意思是:先登录,先退出)