Я наследую от System.Web.Http.AuthorizeAttribute, чтобы создать пользовательскую процедуру авторизации/проверки подлинности, чтобы удовлетворить некоторые необычные требования к веб-приложению, разработанному с использованием ASP.NET MVC 4. Это добавляет безопасность для веб-API, используемый для вызовов Ajax от веб-клиента. Требования:
- Пользователь должен войти в систему каждый раз, когда выполняет транзакцию для проверки кто-то еще не подошел к рабочей станции, после того, как кто-то вошел в систему и ушел.
- Роли не могут быть назначены методам веб-службы во время программы. Они должны назначаться во время выполнения, чтобы администратор мог настройте это. Эта информация хранится в системной базе данных.
Веб-клиент - это одностраничное приложение (SPA), поэтому типичная проверка подлинности форм не работает так хорошо, но я пытаюсь повторно использовать как часть ASP. Как я могу удовлетворить требованиям. Пользовательский 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 не имеет доступа к обновленному Принципиальному, поэтому для IsAuthenticated установлено правильное значение. Это всегда один шаг назад. И я предполагаю, что он использует некоторое кешированное значение, которое не обновляется до тех пор, пока не появится обратная связь с веб-клиентом.
Итак, все это приводит к моему конкретному вопросу, который есть, есть ли другой способ установить IsAuthenticated правильное значение для текущего Принципала без использования файлов 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);
}
}
Это позволяет мне вернуть код состояния Forbidden для веб-клиента, если сбой произошел из-за авторизации вместо аутентификации, и он может ответить соответствующим образом.
Итак, каков правильный способ установить IsAuthenticated для текущего Принципа в этом сценарии?