401 неавторизованный при отправке ajax-запроса в web api
Я уже 2 дня чешу в затылке. Я использую WebAPI версии 2.2, и я использую CORS. Эта настройка работает на стороне сервера, мне разрешено получать авторизованный контент из моего кода сервера веб-клиента, но получать несанкционированные вызовы ajax.
вот моя конфигурация:
конфигурация Web API
WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.Filters.Add(new HostAuthenticationFilter(DefaultAuthenticationTypes.ApplicationCookie));
//enable cors
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new ValidationActionFilter());
}
}
Автозагрузка.Автор.cs:
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(UserContext<ApplicationUser>.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieHttpOnly = true,
CookieName = "Outpour.Api.Auth"
}
);
//app.UseCors(CorsOptions.AllowAll);
//app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
(Я пробовал каждую комбинацию приложение.UseCors (CorsOptions.AllowAll) и config.EnableCors())
мой контроллер атрибутов:
[Authorize]
[EnableCors("http://localhost:8080", "*", "*", SupportsCredentials = true)]
[RoutePrefix("api/videos")]
public class VideosController : ApiController...
Веб-Клиенте
Ajax Вызов:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
options.crossDomain = {
crossDomain: true
};
options.xhrFields = {
withCredentials: true
};
});
function ajaxGetVideoResolutionList() {
var request = {
type: "GET",
dataType: "json",
timeout: Outpour.ajaxTimeOut,
url: Outpour.apiRoot + "/videos/resolutions"
};
$.ajax(request).done(onAjaxSuccess).fail(onAjaxError);
Создание Cookie:
var result = await WebApiService.Instance.AuthenticateAsync<SignInResult>(model.Email, model.Password);
FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe);
var claims = new[]
{
new Claim(ClaimTypes.Name, result.UserName), //Name is the default name claim type, and UserName is the one known also in Web API.
new Claim(ClaimTypes.NameIdentifier, result.UserName) //If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim.
};
var authTicket = new AuthenticationTicket(new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie), new AuthenticationProperties
{
ExpiresUtc = result.Expires,
IsPersistent = model.RememberMe,
IssuedUtc = result.Issued,
RedirectUri = redirectUrl
});
byte[] userData = DataSerializers.Ticket.Serialize(authTicket);
byte[] protectedData = MachineKey.Protect(userData, new[] { "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware", DefaultAuthenticationTypes.ApplicationCookie, "v1" });
string protectedText = TextEncodings.Base64Url.Encode(protectedData);
Response.Cookies.Add(new HttpCookie("Outpour.Api.Auth")
{
HttpOnly = true,
Expires = result.Expires.UtcDateTime,
Value = protectedText
});
и последнее, но не менее, мои заголовки.
Remote Address:127.0.0.1:8888
Request URL:http://127.0.0.1/api/videos/resolutions
Request Method:GET
Status Code:401 Unauthorized
**Request Headersview source**
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Host:127.0.0.1
Origin:http://localhost:8080
Pragma:no-cache
Proxy-Connection:keep-alive
Referer:http://localhost:8080/video/upload
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
**Response Headersview source**
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:8080
Cache-Control:no-cache
Content-Length:61
Content-Type:application/json; charset=utf-8
Date:Wed, 08 Oct 2014 04:01:19 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/8.0
WWW-Authenticate:Bearer
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Developer tools и fiddler утверждают, что с запросом не было отправлено никаких файлов cookie.
2 ответов
Я считаю, что вы смешиваете между аутентификацией cookies и токенами на предъявителя здесь, вы не отправляете токен доступа в заголовке авторизации с вашим запросом, поэтому вы продолжаете получать 401.
Также вам нужно только разрешить CORS с помощью application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
и удалите его еще где из вашего атрибута контроллеров даже из конфигурации.
проверить здесь РЕПО где я реализовал CORS и передний конец AngularJS тоже. он работает правильно. Вот live demo слишком для этого РЕПО, откройте инструменты разработчика и контролировать запросы, вы должны увидеть запрос перед полетом, прежде чем увидеть ваш запрос HTTP get.
Если вам нужно просто защитить свой API с помощью токенов-носителей, я рекомендую вам прочитать Аутентификация На Основе Токенов в должности
это может быть потому, что ваш API не находится на URL-адресе в качестве вызывающего приложения. Ваш URL для API:
http://127.0.0.1/
(игнорируя путь к папке, которая не имеет значения)
..но ты звонишь из http://127.0.0.1:8888
который считается отдельным сайтом, поскольку порт отличается. Поскольку браузер считает, что сайт отличается, он не будет отправлять cookie.
вы пробовали протестировать его со страницы, размещенной на том же URL-адресе, что и API (с тем же портом)?
самое главное: проверьте, что вы можете видеть, что Cookie отправляется в Fiddler.
вы также можете найти более актуальную информацию о том, как заставить это работать на этот ответ