c# - 如何在 MVC 4 应用程序中进行单用户登录

标签 c# asp.net asp.net-mvc-4 session simplemembership

我正在实现一个应用程序,公司中的每台机器都有一个机械师使用该应用程序。我正在尝试实现一项用户策略,如果用户处于角色“Mechanic”——使用用户名 Machine1,并登录该机器,则只有一个用户可以同时使用 Machine1 用户名登录公司。 如果其他人尝试使用相同的用户名登录,则应该阻止并通知已经有用户登录。当 session 超时到期时,我应该注销登录用户并释放要使用的登录名。当用户自己注销时也会发生同样的情况。我正在尝试在 asp.net MVC 4 应用程序上构建它。

我考虑过在数据库中使用 SessionId、UserId 和 IsLoggedIn bool 值。但在这种情况下,我需要更改 MVC 应用程序中 session 超时的登录标志以写入数据库,如果有很多用户登录,这似乎有点过分了。

实现会是什么样的?我应该使用哪些方法或属性来处理数据库中的 session 管理?

仅供引用

我已经创建了自己的方法来检查用户是否已登录,这里是:

public static bool ValidateUser(string username, string password, string companyName)
{
    int? companyId = myRepository.GetCompanyId(companyName);

    int? userId = companyId == 0 ? null : myRepository.GetUserId(username, companyId);

    if (userId.HasValue && userId.Value != 0)
    {
        var userKey = Security.GenerateUserKey(username, companyName);
        return WebSecurity.Login(userKey, password);
    }
    else
    {
        return false;
    }
}

在此方法中,我可以以某种方式检查 session ID 是否与数据库中的相同。

最佳答案

这个问题的症结在于知道用户何时注销以允许下一个同名用户登录。我不知道在 Web 应用程序中执行此操作的精确方法,但这里有一种方法可以通过控制登录持续时间来近似了解用户何时注销。为了对此进行测试,我将超时设置为 1 分钟,这样我就可以快速测试具有相同用户名的不同用户之间的切换。您可以通过 web.config 控制它。

<forms loginUrl="~/Account/Login" timeout="1" slidingExpiration="false" />

请注意,我将 slidingExpiration 设置为 false 以准确了解他们何时注销。如果您使用滑动过期,则无法预测注销实际发生的时间,因为您不能指望用户实际注销。

为了跟踪当前登录的用户,我使用了 MemoryCache 并使用其过期策略为我自动跟踪时间。这是我写的一个简单的帮助程序类来管理它。

public class UserManager
{
    public static bool IsLoggedIn(string username)
    {
        ObjectCache cache = MemoryCache.Default;
        return !string.IsNullOrEmpty(cache[username] as string);

    }

    public static void SetToLoggedIn(string username)
    {
        ObjectCache cache = MemoryCache.Default;
        CacheItemPolicy policy = new CacheItemPolicy();
        //Expires after 1 minute.
        policy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(1));
        cache.Set(username, username, policy);

    }
}

请注意,我使用了 AbsoluteExpiration 并将超时设置为我为表单例份验证设置的相同长度。这会在对象写入后 1 分钟内从缓存中清除该对象。这样我就可以检查缓存中是否存在对象,以确定用户登录的分配时间是否已过。我使用用户名作为缓存对象的键,因为我们正在检查具有该用户名的用户是否在任何时候都在系统中。

现在我们只需将登录操作更改为如下所示。

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid )
        {
            if (UserManager.IsLoggedIn(model.UserName))
            {
                ModelState.AddModelError("", "A user with that user name is already logged in.");
                return View(model);
            }
            if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                UserManager.SetToLoggedIn(model.UserName);
                return RedirectToLocal(returnUrl);
            }
        }

        // If we got this far, something failed, redisplay form
        ModelState.AddModelError("", "The user name or password provided is incorrect.");
        return View(model);
    }

我使用 SimpleMembership 在 MVC 4 应用程序上对此进行了测试,它可以正常工作。我可以看到这种方法的唯一缺点是您将需要绝对超时而不是滑动。获得正确的超时设置对于减少用户在特定时间间隔注销的挫败感以及最大限度地减少其他用户必须等待登录的时间至关重要。

关于c# - 如何在 MVC 4 应用程序中进行单用户登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20659080/

相关文章:

C# ASP.NET cs0246 问题

javascript - 修改 URL 允许某些用户看到他们不应该看到的内容

c# - ASPX页面中的脚本标记被部分写入(输出随机停止)

mysql - 使用 MySql + Entity Framework 的 Asp.Net 应用程序

c# - BadImageFormatException 调试以 x64 模式运行的网站

c# - 使用 C# 添加 entityFramework 部分

c# - 如何在不使用 for 或 foreach 循环的情况下遍历数据表值,然后将列表值添加到列表中?

asp.net - 单元测试通用处理程序

asp.net-mvc-4 - 访问 Startup.Auth.cs 之外配置的 CookieAuthenticationOptions.LoginPath

c# - ASP.NET MVC 中基于不同角色的条件只读/可编辑属性