Проблема ASP.NET WebApi FormsAuthentication 401 (неавторизованная)
Я изучал, как работает авторизация в ASP.Net WebApi, и натолкнулся на ответ Дарина Димитрова в другой публикации ( Аутентификация ASP.NET Web API), и мне нужна помощь, чтобы понять, почему я получаю 401.
Следуя коду Дарина, я создал проект WebApi и добавил следующие контроллеры и модель:
AccountController.cs
using System.Web.Http;
using System.Web.Security;
using AuthTest.Models;
namespace AuthTest.Controllers
{
public class AccountController : ApiController
{
public bool Post(LogOnModel model)
{
if (model.Username == "john" && model.Password == "secret")
{
FormsAuthentication.SetAuthCookie(model.Username, false);
return true;
}
return false;
}
}
}
UsersController.cs
using System.Web.Http;
namespace AuthTest.Controllers
{
[Authorize]
public class UsersController : ApiController
{
public string Get()
{
return "This is top secret material that only authorized users can see";
}
}
}
LogOnModel.cs
namespace AuthTest.Models
{
public class LogOnModel
{
public string Username { get; set; }
public string Password { get; set; }
}
}
Я создал приложение Web Forms с двумя кнопками и ярлыком для целей тестирования.
Default.aspx.cs
using System;
using System.Net.Http;
using System.Threading;
namespace AuthTestWebForms
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ButtonAuthorizeClick(object sender, EventArgs e)
{
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsJsonAsync(
"http://localhost/authtest/api/account",
new { username = "john", password = "secret" },
CancellationToken.None
).Result;
response.EnsureSuccessStatusCode();
bool success = response.Content.ReadAsAsync<bool>().Result;
if (success)
{
//LabelResponse.Text = @"Credentials provided";
var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
LabelResponse.Text = secret.Result;
}
else
{
LabelResponse.Text = @"Sorry, you provided the wrong credentials";
}
}
}
protected void ButtonTestAuthClick(object sender, EventArgs e)
{
using (var httpClient = new HttpClient())
{
var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
LabelResponse.Text = secret.Result;
}
}
}
}
Когда я нажимаю кнопку и запускаю ButtonAuthorizeClick(), он запускает контроллер для учетной записи, а затем запускает контроллер для пользователей, и все в порядке.
Если я затем нажимаю ButtonTestAuthClick(), я получаю ошибку 401 (неавторизовано).
Когда я ищу файл cookie ASPXAUTH в Chrome или FireFox, я не вижу его, поэтому я не на 100% уверен, почему ButtonAuthorizeClick () работает и что мне нужно сделать, чтобы заставить ButtonTestAuthClick () работать.
Спасибо за любую помощь, кто-нибудь может бросить мой путь.
3 ответа
У меня была похожая проблема, но не через страницу клиента Web Forms, а с вызовами JavaScript и AJAX. Оказывается, я вышел из режима аутентификации в web.config, оставленном в "None". Очевидно, что здесь необходимо включить проверку подлинности с помощью форм, чтобы метод FormsAuthentication.SetAuthCookie() имел какой-либо эффект.
<authentication mode="Forms" />
Как только я исправил это упущение, все начало работать нормально.:-)
Вы вызываете веб-API с аутентификацией в середине. Почему бы вам не аутентифицировать пользователя на стороне клиента с помощью ajax?
Проблема здесь в том, что каждый раз, когда вы отправляете запрос в web api HttpClient, это фактически новый веб-запрос, обрабатываемый сервером. Вся информация о файлах cookie не будет сохранена в текущем запросе. Для поддержки этого сценария вам необходимо самостоятельно обработать файл cookie.
Например: Установите cookie ASPXAUTH в заголовки asp.net в методе ButtonAuthorizeClick, если ответ есть. Установите для файла cookie ASPXAUTH значение HttpRequestMessage и отправьте его с помощью HttpClient.
Web api недавно добавил поддержку использования HttpServer для создания in-proc сервера и может напрямую отправлять запрос текущему обработчику сообщений в текущем процессе. Таким образом, вы можете написать код, как:
HttpClient c = new HttpClient(new HttpServer(GlobalConfiguration.DefaultHandler));
c.GetStringAsync("http://localhost/api/Values").Wait();
Чтобы отправить ваш запрос in-proc, чтобы заголовок cookie, заданный в действии web api, все еще находился в конвейере текущего запроса. Регистрация, кажется, не в версии RTM. Вы можете попробовать это ночная сборка http://aspnetwebstack.codeplex.com/discussions/353867.
Хотя уже поздно, клиент в ButtonTestAuthClick не является браузером. Это объект httpClient здесь. Таким образом, вам нужно программно установить куки, сгенерированные из другой кнопки.