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

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

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

  1. 如果brower中的javascript被关闭。
  2. 如果用户没有单击注销并直接关闭浏览器。

请给我一些建议。

谢谢

haan​​si

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

  1. 在数据库中保持一个标志; 每次登录/退出时都会更新标志。 例如,在每个身份validation请求时,如果该标志已经为真,您可以拒绝登录请求。

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

– 编辑 –

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

因此,当用户登录时:

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

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

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

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

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

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

  1. 用户有一个cookie令牌来certificate他们已经在过去的某个时间点登录 – 这对于向他们显示受限制的站点内容很好。
  2. 用户实际上已在此会话中提供了他们的登录详细信息 – 在向他们显示任何个人详细信息(电子邮件地址,首选项,保存的工作搜索等)时,这是必需的

您几乎可以在任何系统中找到的主要问题:

  1. 使用用户IP地址是不可靠的 – 企业用户,代理人之后的人等通常共享一个IP地址,因此“看起来”是同一个用户。
  2. 依赖用户注销是不可靠的 – 用户计算机/浏览器可能崩溃而没有给他们注销的机会,用户可能/将忘记注销。
  3. 依赖会话超时是不可靠的 – 如果您不使用InProc会话,则SessionEnd事件永远不会触发,如果您的服务器崩溃,则不会调用该事件等。

您可以通过我的解决方案找到的问题是:

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

回应评论

回答您的具体问题:

  1. 默认的Profile Provider将数据存储在与成员资格提供程序相同的SQL数据库中(这些表与成员资格和角色表一起创建)。 如果你要将它“存储在缓存中”,这就需要是全局应用程序缓存, 就像KMan在选项2中建议的那样 – 并且正如指出的那样,你需要为此建立一个超时,这导致了可靠地确定这个问题。
  2. 用户不会注销:这是在我们的系统中处理的,不会锁定未来的用户,而是锁定以前登录的用户 – 所以:
    • Alice来到该网站,登录,开始浏览。
    • Bob来到该网站,并使用Alice的详细信息登录,开始浏览。
    • Alice试图继续浏览,被锁定,必须再次登录。
    • 鲍勃现在被锁定了。
    • 等等

最基本的,这不会阻止用户共享他们的登录,但会导致他们烦恼,迫使他们继续登录。如果需要,可以为登录过程添加延迟 – 所以如果尝试不同的会话ID在会话超时(默认为20分钟)或其他时间(例如,基于用户在页面上花费的平均时间)登录站点,然后拒绝登录尝试。

我们所做的是使用Session状态和Application状态的组合来防止重复登录。

当用户登录时,他的userId从asp.net成员资格数据库中检索并作为唯一对象保存在Application状态中。

由于Application状态对应用程序是全局的而不是特定于用户会话,因此我们可以检查userId是否已经保存在Application状态。 如果已经保存,我们可以通知用户并停止登录。 当会话到期时(在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); } } } 

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

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

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

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

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

这就是我的方式。

用户登录后,检查数据库中的标志和sessionID,如果发现使用相同的帐户和不同的sessionID登录(比较新生成的当前会话ID和来自数据库的会话ID),请提醒用户“系统检测到您没有从上次登录时退出,单击<“确定”>以注销上次登录并创建新会话。“ 如果没问题,只需将旧的SessionId替换为DB中的当前SessionID即可。

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

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

希望这有帮助,谢谢……

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

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