web-dev-qa-db-ja.com

ASP.net Core WebAPIでCORSを有効にする方法

私がやろうとしていること

私はAzure Free Plan(ソースコード: https://github.com/killerrin/Portfolio-Backend )でホストされているバックエンドASP.NetコアWeb APIを持っています。

私はそのAPIを利用したいクライアントWebサイトもあります。クライアントアプリケーションはAzure上でホストされるのではなく、Github Pagesまたは他のWebホスティングサービス上でアクセスされます。このため、ドメイン名は並びません。

これを検討するには、Web API側でCORSを有効にする必要がありますが、ここでは数時間にわたってほぼすべてを試してみましたが、機能しません。

クライアントのセットアップ方法 React.jsで書かれた単なる単純なクライアントです。 JqueryのAJAXを通じてAPIを呼び出しています。 Reactサイトは機能するので、そうではないことがわかります。 Jquery API呼び出しは、試行1で確認したとおりに機能します。ここで、呼び出し方法を説明します。

    var apiUrl = "http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication";
    //alert(username + "|" + password + "|" + apiUrl);
    $.ajax({
        url: apiUrl,
        type: "POST",
        data: {
            username: username,
            password: password
        },
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            var authenticatedUser = JSON.parse(response);
            //alert("Data Loaded: " + authenticatedUser);
            if (onComplete != null) {
                onComplete(authenticatedUser);
            }
        },
        error: function (xhr, status, error) {
            //alert(xhr.responseText);
            if (onComplete != null) {
                onComplete(xhr.responseText);
            }
        }
    });

私が試したことがあるもの


試行1 - '正しい'方法

https://docs.Microsoft.com/ja-jp/aspnet/core/security/cors

私はMicrosoftのWebサイトでこのチュートリアルに従ってTを起動し、Startup.csでグローバルに有効にする3つのオプションをすべて試し、すべてのコントローラで設定し、すべてのアクションで試しました。

この方法に従うと、クロスドメインは機能しますが、単一のコントローラー上の単一のアクション(AccountControllerへのPOST)に対してのみ機能します。それ以外のすべてについては、Microsoft.AspNetCore.Corsミドルウェアはヘッダーを設定することを拒否します。

NUGETを介してMicrosoft.AspNetCore.Corsをインストールしました。バージョンは1.1.2です。

これがStartup.csで設定した方法です。

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add Cors
        services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        }));

        // Add framework services.
        services.AddMvc();
        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new CorsAuthorizationFilterFactory("MyPolicy"));
        });

        ...
        ...
        ...
    }

    // This method gets called by the runtime. Use this method to configure 
    //the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        // Enable Cors
        app.UseCors("MyPolicy");

        //app.UseMvcWithDefaultRoute();
        app.UseMvc();

        ...
        ...
        ...
    }

ご覧のとおり、私は言われたとおりにすべてをやっています。私はMVCの前にCorsを追加し、それがうまくいかなかったとき、私はすべてのコントローラーに[EnableCors("MyPolicy")]を置くことを試みました

[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class AdminController : Controller

試み2 - 総当り

https://andrewlock.net/adding-default-security-headers-in-asp-net-core/ /

数時間前の試みを試みた後、私は私がヘッダーを手動で設定しようとすることによってそれを強要することを試みることを考え出しました。このチュートリアルの後に、すべての応答にヘッダーを手動で追加する方法について説明しました。

これらは私が追加したヘッダーです

.AddCustomHeader("Access-Control-Allow-Origin", "*")
.AddCustomHeader("Access-Control-Allow-Methods", "*")
.AddCustomHeader("Access-Control-Allow-Headers", "*")
.AddCustomHeader("Access-Control-Max-Age", "86400")

これらは私が試した失敗した他のヘッダーです

.AddCustomHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
.AddCustomHeader("Access-Control-Allow-Headers", "content-type, accept, X-PINGOTHER")
.AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Host, User-Agent, Accept, Accept: application/json, application/json, Accept-Language, Accept-Encoding, Access-Control-Request-Method, Access-Control-Request-Headers, Origin, Connection, Content-Type, Content-Type: application/json, Authorization, Connection, Origin, Referer")

この方法では、クロスサイトヘッダーが正しく適用され、開発者コンソールとPostmanに表示されます。しかし問題は、それがAccess-Control-Allow-Originチェックに合格している間、ウェブブラウザが415 (Unsupported Media Type)を示すAccess-Control-Allow-Headersに厄介なフィットを投げるということです。

だからブルートフォース法もうまくいきません


最後に

だれかがこれをうまく動かして手を貸すことができるか、あるいは私を正しい方向に向けることができるでしょうか。


EDIT

そのため、API呼び出しを通過させるには、JQueryの使用をやめて、Pure JavascriptのXMLHttpRequest形式に切り替える必要がありました。

試行1

私はMicrosoft.AspNetCore.Corsapp.UseCorsの前に置くConfigureメソッド内を除いて、MindingDataの答えに従うことによってapp.UseMvcを機能させることができました。

さらに、ワイルドカードをサポートするためのJavascript APIソリューションoptions.AllowAnyOrigin()と組み合わせると、同様に機能するようになりました。

試行2

それで、Access-Control-Allow-Originのワイルドカードが機能しないという唯一の例外を除いて、Attempt 2(ブルートフォース)を機能させることに成功しました。そのため、アクセス可能なドメインを手動で設定する必要があります。

このWebAPIを全員に広く公開してもらいたいので、そのことは明らかに理想的ではありませんが、少なくとも別のサイトではうまくいきます。

app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
    .AddDefaultSecurePolicy()
    .AddCustomHeader("Access-Control-Allow-Origin", "http://localhost:3000")
    .AddCustomHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE")
    .AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type, Authorization"));
106
killerrin

非常に単純なCORSポリシー(XXXドメインからのすべての要求を許可)があるので、それをそれほど複雑にする必要はありません。最初に次のことを試してみてください(CORSの非常に基本的な実装)。

まだ行っていない場合は、CORS nugetパッケージをインストールしてください。

Install-Package Microsoft.AspNetCore.Cors

Startup.csのConfigureServicesメソッドに、CORSサービスを追加します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
}

次に、startup.csのConfigureメソッドに以下を追加します。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseCors(
        options => options.WithOrigins("http://example.com").AllowAnyMethod()
    );

    app.UseMvc();
}

今それをやってみましょう。ポリシーは、アクションごとに異なるポリシーが必要な場合(たとえば、異なるホストや異なるヘッダー)に適しています。あなたの単純な例では、あなたは本当にそれを必要としません。この簡単な例から始めて、必要に応じて微調整してください。

さらに読む: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

154
MindingData
  • ConfigureServices add services.AddCors(); services.AddMvc()の前に。
  • Configure にUseCorsを追加します。

    app.UseCors(builder => builder
        .AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());   
    app.UseMvc();
    

重要な点は、app.UseMvc()の前にapp.UseCorsを追加することです。

MVCの前にCORS機能を宣言して、MVCパイプラインが制御を取得して要求を終了する前にミドルウェアが起動するようにしてください。

138
Ji Ra

私は私のために働いた私自身のミドルウェアクラスを作成しました、私は.netコアミドルウェアクラスに何か問題があると思います

public class CorsMiddleware
{
    private readonly RequestDelegate _next;

    public CorsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
        httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
    public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CorsMiddleware>();
    }
}

そしてstartup.csでこのようにそれを使用しました

app.UseCorsMiddleware();
22
user8266077

私の場合、MindingDataの答えによれば、getリクエストのみがうまく機能します。他の種類の要求のためにあなたは書く必要があります:

app.UseCors(corsPolicyBuilder =>
   corsPolicyBuilder.WithOrigins("http://localhost:3000")
  .AllowAnyMethod()
  .AllowAnyHeader()
);

.AllowAnyHeader()を追加することを忘れないでください

14
Towhid

user8266077 s answer に展開すると、.NET Core 2.1のプレビューで プリフライトリクエスト にOPTIONSレスポンスを指定する必要があることがわかりました。 :

// https://stackoverflow.com/a/45844400
public class CorsMiddleware
{
  private readonly RequestDelegate _next;

  public CorsMiddleware(RequestDelegate next)
  {
    _next = next;
  }

  public async Task Invoke(HttpContext context)
  {
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    // Added "Accept-Encoding" to this list
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Accept-Encoding, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
    // New Code Starts here
    if (context.Request.Method == "OPTIONS")
    {
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      await context.Response.WriteAsync(string.Empty);
    }
    // New Code Ends here

    await _next(context);
  }
}

そしてStartup.csのようにミドルウェアを有効にしました

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
7
ckr

上記の手順のどれも助けにならず、私はそれから article を読んで問題を解決しました。

以下はそのコードです。

public void ConfigureServices(IServiceCollection services)
{
    // Add service and create Policy with options
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials() );
    });


    services.AddMvc(); 
}

そして

public void Configure(IApplicationBuilder app)
{
    // ...

    // global policy - assign here or on each controller
    app.UseCors("CorsPolicy");

そして私の行動方法の上に

[EnableCors("CorsPolicy")]
4
Sainath

ajax呼び出しの前にjQuery.support.cors = true;を追加してみてください

また、APIに送信したデータが不思議である可能性もあります。

次のJSON関数を追加してみてください

        var JSON = JSON || {};

    // implement JSON.stringify serialization
    JSON.stringify = JSON.stringify || function (obj) {

        var t = typeof (obj);
        if (t != "object" || obj === null) {

            // simple data type
            if (t == "string") obj = '"' + obj + '"';
            return String(obj);

        }
        else {

            // recurse array or object
            var n, v, json = [], arr = (obj && obj.constructor == Array);

            for (n in obj) {
                v = obj[n]; t = typeof (v);

                if (t == "string") v = '"' + v + '"';
                else if (t == "object" && v !== null) v = JSON.stringify(v);

                json.Push((arr ? "" : '"' + n + '":') + String(v));
            }

            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
        }
    };

    // implement JSON.parse de-serialization
    JSON.parse = JSON.parse || function (str) {
        if (str === "") str = '""';
        eval("var p=" + str + ";");
        return p;
    };

それからあなたのデータで:objectそれをに変更する

    data: JSON.stringify({
        username: username,
        password: password
    }),
4
Riaan Saayman

MindingDataの回答に対するあなたのコメントに基づいて、それはあなたのCORSとは無関係です、それはうまく機能しています。

あなたのコントローラーのアクションは間違ったデータを返しています。 HTTPコード415は、「サポートされていないメディアタイプ」を意味する。これは、間違ったフォーマットをコントローラに渡した場合(つまり、XMLをjsonのみを受け入れるコントローラに渡した場合)、または間違った型を返した場合(xmlのみを返すように宣言されたコントローラでXmlを返す場合)に発生します。

後であなたの行動に[Produces("...")]attributeの存在をチェックするために

2
Tseng

LaunchSettings.jsonのiisSettingsで、anonymousAuthenticationをtrueに設定します。

"iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:4200/",
      "sslPort": 0
    }
  }

次に、Startup.csのConfigureServicesで、services.AddMvcの前に、次を追加します。

services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
{
    builder
        .AllowAnyOrigin()
        .WithHeaders(HeaderNames.AccessControlAllowHeaders, "Content-Type")
        .AllowAnyMethod()
        .AllowCredentials();
}));

そして、configureメソッドで、app.UseMvc()を追加する前に:

app.UseCors("ApiCorsPolicy");
1
Adrian

あなたがあなた自身の _ cors _ ミドルウェアを使うのなら、 Origin headerをチェックして、それが本当に _ cors _ requestであることを確認する必要があると思います。

 public class CorsMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMemoryCache _cache;
    private readonly ILogger<CorsMiddleware> _logger;

    public CorsMiddleware(RequestDelegate next, IMemoryCache cache, ILogger<CorsMiddleware> logger)
    {
        _next = next;
        _cache = cache;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context, IAdministrationApi adminApi)
    {
        if (context.Request.Headers.ContainsKey(CorsConstants.Origin) || context.Request.Headers.ContainsKey("Origin"))
        {
            if (!context.Request.Headers.TryGetValue(CorsConstants.Origin, out var Origin))
            {
                context.Request.Headers.TryGetValue("Origin", out Origin);
            }

            bool isAllowed;
            // Getting Origin from DB to check with one from request and save it in cache 
            var result = _cache.GetOrCreateAsync(Origin, async cacheEntry => await adminApi.DoesExistAsync(Origin));
            isAllowed = result.Result.Result;

            if (isAllowed)
            {
                context.Response.Headers.Add(CorsConstants.AccessControlAllowOrigin, Origin);
                context.Response.Headers.Add(
                    CorsConstants.AccessControlAllowHeaders,
                    $"{HeaderNames.Authorization}, {HeaderNames.ContentType}, {HeaderNames.AcceptLanguage}, {HeaderNames.Accept}");
                context.Response.Headers.Add(CorsConstants.AccessControlAllowMethods, "POST, GET, PUT, PATCH, DELETE, OPTIONS");

                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("CORS with Origin {Origin} was handled successfully", Origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                await _next(context);
            }
            else
            {
                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("Preflight CORS request with Origin {Origin} was declined", Origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                _logger.LogInformation("Simple CORS request with Origin {Origin} was declined", Origin);
                context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                return;
            }
        }

        await _next(context);
    }
1
Riddik

私にとっては、使用していたコードとは関係ありません。 Azureの場合は、サイドメニューのエントリ「CORS」にあるApp Serviceの設定に入る必要がありました。そこに私はものを要求していたドメインを追加しなければなりませんでした。それが入ったら、すべてが魔法でした。

1
kjbetz

最も簡単なソリューションは追加です

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(options => options.AllowAnyOrigin());

        app.UseHttpsRedirection();
        app.UseMvc();
    }

startup.csへ。

0
amilamad

上記のMindingDataの答えは機能しましたが、Microsoft.AspNetCore.CorsではなくMicrosoft.AspNet.Corsを使用する必要がありました。 Visual Studio 2019で.NetCore Web Application APIプロジェクトを使用しています

0
carl