【问题标题】:Drop user authenticated in ASP.NET MVC删除在 ASP.NET MVC 中经过身份验证的用户
【发布时间】:2016-10-31 23:20:31
【问题描述】:

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

我们有一个用户管理,允许用户编辑/删除其他用户。 在删除功能上,目前我只在数据库上执行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 将他从数据库中删除时,有没有办法在 IIS 上删除 ABC 会话? 我不知道.. 强制 cookie 过期。我只是不想为导航中完成的每个操作实施咨询,以检查用户在数据库中是否仍然“活着”。

有什么想法、建议吗?

【问题讨论】:

    标签: c# asp.net-mvc authorize-attribute


    【解决方案1】:

    首先,不。无法在另一个会话中访问 c​​ookie,因为它们仅在请求/响应的生命周期内存在。但是,您可以存储所有当前经过身份验证的用户的静态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 interface 来做到这一点...在 c# 中一定有一些可能。
    • 您可以创建自己的会话处理程序并枚举它们 - 但这几乎就是 List&lt;string&gt; 正在做的事情。服务器端不存在 Cookie,因此无法更改不属于当前请求的 Cookie
    • 没有别的事可做?我的意思是没有办法 formsauthentication.signout() 传递 id 例如?到signout() 远程用户?
    • 否,因为应用程序不管理用户是否在服务器端登录。用户只有一个 cookie,表明他们已登录,并且服务器承认这一点。 Forms auth 模块只检查它是否可以解密 cookie,以及它是否没有过期。所有这些信息都存储在 cookie 中,而不是服务器上。让它工作的唯一方法是管理“登录”状态的服务器端。
    猜你喜欢
    • 2021-01-10
    • 1970-01-01
    • 2015-04-20
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多