web-dev-qa-db-ja.com

Web Api 2およびOWINトークン認証でCORSを有効にします

Knockoutjsを使用してWebApi 2プロジェクト(localhost:82)から関数を呼び出し、CORSを有効にする2つのプロジェクト間の通信を行うASP.NET MVC 5 webproject(localhost:81)があります。 OWINトークン認証をWebApiに実装しようとするまで、これまでのところすべてが機能します。

WebApiで/ tokenエンドポイントを使用するには、エンドポイントでCORSを有効にする必要もありますが、ソリューションを何時間も試して検索した後でも動作し、api/tokenの結果は次のようになります。

XMLHttpRequest cannot load http://localhost:82/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. 

public void Configuration(IAppBuilder app)
{
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    TokenConfig.ConfigureOAuth(app);
    ...
}

TokenConfig

public static void ConfigureOAuth(IAppBuilder app)
{
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);

    OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
        Provider = new SimpleAuthorizationServerProvider()
    };

    app.UseOAuthAuthorizationServer(OAuthServerOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}

AuthorizationProvider

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

    var appUserManager = context.OwinContext.GetUserManager<AppUserManager>();
    IdentityUser user = await appUserManager.FindAsync(context.UserName, context.Password);

    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    }
    ... claims
}

IdentityConfig

public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
    // Tried to enable it again without success. 
    //context.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});

    var manager = new AppUserManager(new UserStore<AppUser>(context.Get<ApplicationDbContect>()));

    ...

    var dataProtectionProvider = options.DataProtectionProvider;
    if (dataProtectionProvider != null)
    {
        manager.UserTokenProvider =
                new DataProtectorTokenProvider<AppUser>(dataProtectionProvider.Create("ASP.NET Identity"));
    }
    return manager;
}

編集:

1。重要な点は、エンドポイント(localhost:82/token)を直接開くことです。

2。WebプロジェクトからApi(localhost:82/api/..)を呼び出すことも機能するため、CORSはWebApiに対して有効になっています。

27
Sam

あなたの問題はコメント内で解決されましたが、何が原因で、このクラスの問題全体をどのように解決するかを理解することが重要だと思います。

コードを見ると、トークンエンドポイントにAccess-Control-Allow-Originヘッダーを複数回設定していることがわかります。

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

そしてGrantResourceOwnerCredentialsメソッド内:

context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

CORS仕様 を見ると、これ自体が問題です。

応答にゼロまたは複数のAccess-Control-Allow-Originヘッダー値が含まれる場合、失敗を返し、このアルゴリズムを終了します。

あなたのシナリオでは、フレームワークはこのヘッダーを2回設定し、CORSの実装方法を理解しているため、特定の状況(おそらくクライアント関連)でヘッダーが削除されます。

これは、次の質問の回答でも確認されています。 重複したAccess-Control-Allow-Origin:* CORエラーの原因?

このため、ConfigureOAuthへの呼び出しの後にapp.UseCorsへの呼び出しを移動すると、CORSヘッダーを1回だけ設定できます(owinパイプラインはOAuthミドルウェアで中断され、 TokenエンドポイントのMicrosoft CORSミドルウェアに到達し、Ajax呼び出しを機能させます。

より良いグローバルなソリューションを得るには、OAuthミドルウェアの呼び出しの前にapp.UseCorsを再度配置し、GrantResourceOwnerCredentials内の2番目のAccess-Control-Allow-Origin挿入を削除してください。

42
Federico Dipuma

以下の手順に従ってください。APIが機能します。

  1. 削除 APIからのconfig.EnableCors(), [EnableCors(header:"*"....)]などのコード。
  2. Startup.csおよびaddに移動します

    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    

    ConfigureAuth(app);

この機能を使用するには、UouはMicrosoft.owin.corsパッケージもインストールする必要があります。

9
santosh kumar

App.UseCors()を使用せずに問題を解決する

同じ問題がありました。 Vue.Js client with axoisを使用して、REST-APIにcross-corpsでアクセスしました。私のOwin-Api-Serverでは、Microsoft.Owin.Corsを追加できません他のサードパーティコンポーネントとのバージョンの競合のため、nugetでした。 app.UseCors()を使用できませんでしたメソッドですが、ミドルウェアパイプラインを使用して解決しました。

private IDisposable _webServer = null;

public void Start(ClientCredentials credentials)
{
    ...
    _webServer = WebApp.Start(BaseAddress, (x) => Configuration(x));
    ...
}

public void Configuration(IAppBuilder app)
{
    ...
    // added middleware insted of app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    app.Use<MyOwinMiddleware>();
    app.UseWebApi(config);
    ...
}

public class MyOwinMiddleware : OwinMiddleware
{
    public MyOwinMiddleware(OwinMiddleware next) :
        base(next)
    { }

    public override async Task Invoke(IOwinContext context)
    {
        var request = context.Request;
        var response = context.Response;

        response.OnSendingHeaders(state =>
        {
            var resp = (IOwinResponse)state;

            // without this headers -> client apps will be blocked to consume data from this api
            if (!resp.Headers.ContainsKey("Access-Control-Allow-Origin"))
                resp.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
            if (!resp.Headers.ContainsKey("Access-Control-Allow-Headers"))
                resp.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });
            if (!resp.Headers.ContainsKey("Access-Control-Allow-Methods"))
                resp.Headers.Add("Access-Control-Allow-Methods", new[] { "*" });

            // by default owin is blocking options not from same Origin with MethodNotAllowed
            if (resp.StatusCode == (int)HttpStatusCode.MethodNotAllowed &&
                HttpMethod.Options == new HttpMethod(request.Method))
            {
                resp.StatusCode = (int)HttpStatusCode.OK;
                resp.ReasonPhrase = HttpStatusCode.OK.ToString();
            }

        }, response);

        await Next.Invoke(context);
    }
}

そこで、自分のミドルウェアを作成し、応答を操作しました。 GET呼び出しではAccess-Control-Allowヘッダーのみが必要でしたが、OPTIONS呼び出しではaxois.post()はPOSTを送信する前にOPTIONS-methodで最初に呼び出しているため、StatusCodeを操作する必要もありました。 OPTIONSがStatusCode 405を返す場合、POSTは送信されません。

これで問題が解決しました。たぶんこれは誰かを助けることもできます。

0
jaz