Что я сделал
Я создаю приложение REST-ish WebAPI. Я пытаюсь реализовать аутентификацию форм здесь, поэтому клиенты могут разрешать пользователям входить в систему/регистрироваться/выходить из своих браузеров. Я использую simpleMembership, и пользователи хранятся в моих таблицах базы данных simpleMembership. В качестве первого шага я применил метод входа в свой аккаунт AccountsController:
[System.Web.Http.HttpPost]
public HttpResponseMessage LogIn(LoginModel model)
{
if (ModelState.IsValid)
{
if (User.Identity.IsAuthenticated)
{
return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
}
if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
//TODO: look up by id, not by name
var userProfile = _service.GetUser(WebSecurity.GetUserId(model.UserName));
return Request.CreateResponse(HttpStatusCode.OK, userProfile);
}
else
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
}
// If we got this far, something failed
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
Проблема
Вот что происходит:
- Я установил точку останова в
if (User.Identity.IsAuthenticated)
. - Используя что-то вроде POSTMan или Fiddler, я пытаюсь войти в систему, используя некоторые фиктивные учетные данные.
- Я ударил точку останова и получил "Ложь" для IsAuthenticated, как и ожидалось.
- Я перехожу к следующему "if", и попытка LogIn завершается с ошибкой, как и ожидалось.
- Код в операторе
else
попадает, но после этого возвращается: 1) моя точка останова снова ударяется, а 2) у принципала установлен мой идентификатор Windows. Оба являются неожиданными, и я пытаюсь выяснить, как исправить это.
Ожидаемое поведение
- Метод просто возвращает 401 Unauthorized, поскольку фиктивный пользователь не существует в моей базе данных приложений.
Конфигурация
Я думаю, что это проблема конфигурации. Принцип автоматически устанавливается на мою учетную запись Windows по какой-либо причине при сбое аутентификации. Некоторые подробности, связанные с моей конфигурацией:
<authentication mode="Forms">
<forms loginUrl="~/" timeout="2880" />
</authentication>
- Я не поддерживал проверку подлинности Windows в любом месте приложения. Мой web.config выше ^
- Использование IISManager У меня отключена анонимная аутентификация
- В моем приложении applicationhost.config отключена Windows и анонимная аутентификация
Вопросы
- Почему точка останова ударяется дважды, вместо того, чтобы метод LogIn возвращался неавторизованным, так как это последнее "else" попало?
- Почему мои учетные данные Windows используются для этого неожиданного и нежелательного "loopback"?
- Как я могу предотвратить это? ИЛИ:
- Нужно ли использовать MessageHandler для установки принципала? Если да, то как это влияет на [Аутентификация] и IsAuthenticated? Любые примеры?
Обновление 1
Я пробовал зарегистрировать следующий обработчик:
public class PrincipalHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken
cancellationToken)
{
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
Thread.CurrentPrincipal = HttpContext.Current.User;
return await base.SendAsync(request, cancellationToken);
}
}
И теперь директор никогда не настроен на мой идентификатор Windows. Из POSTMan (расширение браузера) оператор if дважды попадает, и я получаю всплывающее окно с запросом учетных данных. Из Fiddler я просто получаю 401 Unauthorized, как и ожидалось.
Новые вопросы
- Как я могу установить принципала в соответствии с тем, что в файле cookie ответа, И проверить подлинность моей простой таблицы членства в приложении?
Обновление 2
Кажется, что это сообщение приводит меня в правильном направлении - используя членство вместо User в моем LoginMethod:
ASP.NET MVC - установка пользовательского IIdentity или IPrincipal
Будет продолжать обновляться с прогрессом, но я по-прежнему открыт для предложений/рекомендаций.
Обновление 3 Я никогда не был так сдержан и разозлен - здесь не требовалось никакого специального обработчика. В моих свойствах проекта была включена авторизация Windows. Рабочее решение для входа и выхода из системы находится здесь и "просто работать" с моими таблицами членства:
public HttpResponseMessage LogIn(LoginModel model)
{
if (ModelState.IsValid)
{
if (User.Identity.IsAuthenticated)
{
return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
}
if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return Request.CreateResponse(HttpStatusCode.OK, "logged in successfully");
}
else
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
}
// If we got this far, something failed
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
public HttpResponseMessage LogOut()
{
if (User.Identity.IsAuthenticated)
{
WebSecurity.Logout();
return Request.CreateResponse(HttpStatusCode.OK, "logged out successfully.");
}
return Request.CreateResponse(HttpStatusCode.Conflict, "already done.");
}