ASP.NET MVC中删除已认证用户

3

我有一个使用ASP.NET MVC 4开发的网络系统。

我们有一个用户管理功能,允许用户编辑/删除其他用户。 在删除功能中,目前我只在数据库上执行了delete操作。

因此,这是我的login控制器/方法:

[HttpPost]
public ActionResult Login(LoginViewModel loginViewModel)
{
    if (_loginService == null)
        _loginService = new LoginService();

    var result = _loginService.Login(loginViewModel.User, loginViewModel.Password);
    if (!result.Error)
    {
        var userData = JsonConvert.SerializeObject(result.User);
        FormsAuthentication.SetAuthCookie(result.User.Id, false);
        var ticket = new FormsAuthenticationTicket(1, result.Id, DateTime.Now, DateTime.Now.AddMinutes(9999), true, userData, FormsAuthentication.FormsCookiePath);
        var encryptedCookie = FormsAuthentication.Encrypt(ticket);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie) { Expires = DateTime.Now.AddHours(14) };

        Response.Cookies.Add(cookie);
    }
    return new JsonResult
    {
        Data = result
    };
}

我会用一些JavaScript来处理客户端的返回结果,目前这个功能运行正常。

对于每一个需要用户进行身份验证的控制器,我都加上了[Authorize]属性。

假设我刚使用用户名为ABC的用户登录。只要ABC的cookie还有效,他就可以正常浏览页面。问题在于,如果有其他用户(比如ZXC)删除了用户ABC,那么他仍然可以正常浏览页面,直到cookie过期。

有没有办法在ZXC从数据库中删除ABC时立即终止ABC的IIS会话呢?我不知道是否可以强制让cookie过期。我只是不想在每次导航时都实现一个查询,以检查用户是否仍然存在于数据库中。

有什么想法或建议吗?

1个回答

2
首先,不行。无法在另一个会话中访问cookie,因为它们只存在于请求/响应的生命周期内。但是,您可以存储所有当前经过身份验证的用户的静态“List”,并以此使其无效。
这有点问题,因为如果应用程序池循环使用,则所有用户都将“注销”。如果对您来说没有问题(即应用程序池在凌晨2点循环使用,并且它是不在凌晨2点运行的业务系统),那么您可以尝试这个...
提供的代码未经测试。
来源:https://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationmodule.authenticate 编辑: 我没有从请求中删除cookie并在响应中使其过期。
在Global.asax中:
private static List<string> _authenticatedUsers = new List<string>();

public static AuthenticateUser (MyApplicationUser user)
{
    if(!_authenticatedUsers.ContainsKey(user.Username))
    {
        _authenticatedUsers.Add(user.Username);
    }
}

public static DeauthenticateUser (MyApplicationUser user)
{
    if(_authenticatedUsers.ContainsKey(user.Username))
    {
        _authenticatedUsers.Remove(user.Username);
    }
}

public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
  if (FormsAuthentication.CookiesSupported)
  {
    if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
    {
      try
      {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
          Request.Cookies[FormsAuthentication.FormsCookieName].Value);

        MyApplicationUser user = JsonConvert.DeserializeObject(ticket.UserData);

        if(user == null || !_authenticatedUsers.Any(u => u == user.Username))
        { 
            // this invalidates the user
            args.User = null;
            Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
            HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
            DateTime now = DateTime.Now;

            myCookie.Value = "a";
            myCookie.Expires = now.AddHours(-1);

            Response.Cookies.Add(myCookie);
            Response.Redirect(FormsAuthentication.LoginUrl);
            Resonpse.End();
        }
      }
      catch (Exception e)
      {
        // Decrypt method failed.
        // this invalidates the user
        args.User = null;
        Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
        HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
        DateTime now = DateTime.Now;

        myCookie.Value = "a";
        myCookie.Expires = now.AddHours(-1);

        Response.Cookies.Add(myCookie);
        Response.Redirect(FormsAuthentication.LoginUrl);
        Resonpse.End();
      }
    }
  }
  else
  {
    throw new HttpException("Cookieless Forms Authentication is not " +
                            "supported for this application.");
  }
}

在您的登录操作中

public ActionResult Login(LoginViewModel loginViewModel)
{
    ...

    if (!result.Error)
    {
        ...
        MvcApplication.AuthenticateUser(result.User);
        ...
    }
    ...
}

在您的注销操作中

public ActionResult Logout(...)
{
    ...
    MvcApplication.DeauthenticateUser(user);
    ...
}

在你的删除方法中
...
MvcApplication.DeauthenticateUser(user);
...

谢谢您的时间。我认为这是一种方法...但我仍然想知道是否有其他选择...我知道在Java中我们可以使用“JMX接口”来实现...在C#中也一定有类似的东西。 - Marllon Nasser
你可以创建自己的会话处理程序并枚举它们 - 但这基本上就是 List<string> 所做的。服务器端不存在 Cookie,因此无法更改不属于当前请求的 Cookie。 - Michael Coxon
还有其他办法吗?我的意思是,没有办法通过传递一个ID之类的参数来调用formsauthentication.signout()方法,以注销远程用户吗? - Marllon Nasser
不行,因为应用程序没有在服务器端管理用户是否已登录。用户只有一个cookie,表示他们已登录,服务器会确认这一点。Forms身份验证模块只检查它是否可以解密cookie,并且它没有过期。所有这些信息都存储在cookie中,而不是服务器上。唯一的方法是在服务器端管理“已登录”状态,才能使其正常工作。 - Michael Coxon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接