Как настроить ASP.NET Web API AuthorizeAttribute для необычных требований

Я наследую отSystem.Web.Http.AuthorizeAttribute создать пользовательскую процедуру авторизации / аутентификации, отвечающую некоторым необычным требованиям для веб-приложения, разработанного с использованием ASP.NET MVC 4. Это повышает безопасность веб-API, используемого для вызовов Ajax из веб-клиента. Требования следующие:

The user must logon each time they perform a transaction to verify someone else has not walked up to the workstation after someone has logged on and walked away. Roles cannot be assigned to the web service methods at program time. They must be assigned at run time so that an administrator can configure this. This information is stored in the system database.

Веб-клиент являетсяодностраничное приложение (SPA) поэтому типичная проверка подлинности с помощью форм работает не так хорошо, но я пытаюсь повторно использовать как можно больше инфраструктуры безопасности ASP.NET для удовлетворения требований. ИндивидуальныеAuthorizeAttribute отлично работает для требования 2 при определении того, какие роли связаны с методом веб-службы. Я принимаю три параметра: имя приложения, имя ресурса и операцию, чтобы определить, какие роли связаны с методом.

public class DoThisController : ApiController
{
    [Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
    public string GetData()
    {
        return "We did this.";
    }
}

Я отменяюOnAuthorization метод, чтобы получить роли и аутентифицировать пользователя. Так как пользователь должен проходить аутентификацию для каждой транзакции, я уменьшаю трату вперед и назад, выполняя аутентификацию и авторизацию на одном шаге. Я получаю учетные данные пользователей от веб-клиента с помощью обычной проверки подлинности, которая передает зашифрованные учетные данные в заголовок HTTP. Так что мойOnAuthorization Метод выглядит так:

public override void OnAuthorization(HttpActionContext actionContext)
{

     string username;
     string password;
     if (GetUserNameAndPassword(actionContext, out username, out password))
     {
         if (Membership.ValidateUser(username, password))
         {
             FormsAuthentication.SetAuthCookie(username, false);
             base.Roles = GetResourceOperationRoles();
         }
         else
         {
             FormsAuthentication.SignOut();
             base.Roles = "";
         }
     }
     else
     {
         FormsAuthentication.SignOut();
         base.Roles = "";
     }
     base.OnAuthorization(actionContext);
 }

GetUserNameAndPassword извлекает учетные данные из заголовка HTTP Затем я используюMembership.ValidateUser проверить учетные данные. У меня есть пользовательский поставщик членства и поставщик ролей, подключенный к пользовательской базе данных. Если пользователь аутентифицирован, я получаю роли для ресурса и операции. Оттуда я использую базуOnAuthorization завершить процесс авторизации. Вот где это ломается.

Если пользователь проходит проверку подлинности, я использую стандартные методы проверки подлинности для входа в систему (FormsAuthentication.SetAuthCookie), а если они не выполняются, я выхожу из системы (FormsAuthentication.SignOut). Но проблема, кажется, в том, что базаOnAuthorization класс не имеет доступа кPrincipal обновляется так, чтобыIsAuthenticated установлен на правильное значение. Это всегда на шаг позади. И я предполагаю, что он использует какое-то кэшированное значение, которое не обновляется до тех пор, пока не произойдет обмен данными в веб-клиенте.

Таким образом, все это приводит к моему конкретному вопросу: есть ли другой способIsAuthenticated на правильное значение для текущегоPrincipal без использования куки? Мне кажется, что файлы cookie не применяются в данном конкретном сценарии, когда мне приходится каждый раз проходить аутентификацию. Причина, которую я знаюIsAuthenticated не установлен на правильное значение, я также переопределитьHandleUnauthorizedRequest метод к этому:

 protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
 {
     if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
     {
         filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
     }
     else
     {
         base.HandleUnauthorizedRequest(filterContext);
     }
 }

Это позволяет мне возвращать код состояния «Запрещено» веб-клиенту, если сбой произошел из-за авторизации вместо аутентификации, и он может ответить соответствующим образом.

Итак, как правильно установитьIsAuthenticated для текущегоPrinciple по этому сценарию?

Ответы на вопрос(3)

Ваш ответ на вопрос