Удаление пользователя, прошедшего проверку подлинности в ASP.NET MVC

У меня есть веб-система, разработанная с помощью 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.

Есть ли способ сбросить ABC сеанс в IIS в момент, когда ZXC удаляет его из базы данных? Я не знаю ... принудительно истечет срок действия куки. Я просто не хочу реализовывать консультации для каждого действия, выполняемого в навигации, чтобы проверить, "жив ли" ли пользователь в базе данных.

Есть идеи, предложения?


person Marllon Nasser    schedule 31.10.2016    source источник


Ответы (1)


Во-первых, нет. Невозможно получить доступ к файлам 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);
...
person Michael Coxon    schedule 31.10.2016
comment
Спасибо за ваше время. Я думаю, что это подход ... но мне все еще интересно, есть ли другие варианты ... Я знаю, что в java мы можем использовать JMX interface для этого ... должно быть что-то, вероятно, в C #. - person Marllon Nasser; 31.10.2016
comment
Вы можете создавать свои собственные обработчики сеансов и перечислять их - но это в значительной степени то, что делает List<string>. Файлы cookie не существуют на стороне сервера, поэтому невозможно изменить тот, который не является частью текущего запроса. - person Michael Coxon; 01.11.2016
comment
Больше нечего делать? Я имею в виду, что нет возможности formsauthentication.signout() передать, например, id? signout() удаленному пользователю? - person Marllon Nasser; 03.11.2016
comment
Нет, потому что приложение не управляет тем, вошел ли пользователь в систему на стороне сервера. У пользователя есть файл cookie, в котором говорится, что он вошел в систему, и сервер подтверждает это. Модуль проверки подлинности форм только проверяет, может ли он расшифровать файл cookie, и что срок его действия не истек. Вся эта информация хранится в cookie, а не на сервере. Единственный способ, чтобы это когда-либо работало, - это управлять состоянием «вошел в систему» ​​на стороне сервера. - person Michael Coxon; 03.11.2016