web-dev-qa-db-ja.com

401WebAPIにajaxリクエストを送信するときに許可されていません

私はこれで2日間頭をかいてきました。 WebAPIバージョン2.2を使用しており、CORSを使用しています。この設定はサーバー側で機能します。Webクライアントサーバーコードから許可されたコンテンツを取得することは許可されていますが、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());
    }
}

Startup.Auth.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);

(app.UseCors(CorsOptions.AllowAll)とconfig.EnableCors()のすべての組み合わせを試しました)

私のコントローラー属性:

[Authorize]
[EnableCors("http://localhost:8080", "*", "*", SupportsCredentials = true)]
[RoutePrefix("api/videos")]
public class VideosController : ApiController...

Webクライアント

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);

クッキーの作成:

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

開発者ツールとフィドラーは、リクエストとともに送信されたCookieはないと主張しています。

8
Dale Marshall

ここではCookie認証とベアラートークンを混在させていると思います。リクエストとともにAuthorizationヘッダーでアクセストークンを送信していないため、401を取得し続けます。また、application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);を使用してCORSを許可するだけで済みます。構成からでもコントローラー属性から他の場所で削除します。

私の ここのリポジトリ ここでCORSを実装し、フロントエンドもAngularJSです。正しく機能しています。これが ライブデモ このリポジトリでも、開発者ツールを開いてリクエストを監視します。HTTPgetリクエストが表示される前に、プリフライトリクエストが表示されます。

ベアラートークンを使用してAPIを保護するだけでよい場合は、 トークンベースの認証 投稿を読むことをお勧めします。

3
Taiseer Joudeh

これは、APIが呼び出し元のアプリケーションとして提供されたURLにないためである可能性があります。 APIのURLは次のとおりです。http://127.0.0.1/(フォルダーパスを無視します-これは重要ではありません)

..しかし、ポートが異なるため、別のサイトとしてカウントされるhttp://127.0.0.1:8888から呼び出しています。ブラウザはサイトが異なると判断するため、Cookieを送信しません。

APIと同じURL(同じポート)でホストされているページからテストしてみましたか?

最も重要なこと:Fiddlerで送信されているCookieを確認できることを確認してください。

また、これを機能させるためのより関連性の高い情報を見つけるかもしれません この回答について

0
NickG