web-dev-qa-db-fra.com

WebAPI ASP.NET Core CORS: pas d'en-tête Access-Control-Allow-Origin

J'ai déployé mon API Web ASP.NET Core sur Azure et je peux accéder à ses points de terminaison à l'aide de Swagger ou d'un débogueur Web tel que Fiddler. Dans les deux cas (même origine dans Swagger, origine différente en utilisant Fiddler de mon ordinateur), lors de l'accès aux API, le résultat attendu est obtenu, avec CORS activé comme suit dans mon Startup.cs:

  1. ajoutez services.AddCors(); à ConfigureServices.

  2. ajoutez le middleware à Configure: je suis conscient que l'ordre ici est important ( ASP.NET 5: accès-contrôle-autorisation-origine en réponse ), je passe donc cet appel à le haut de la méthode, précédé uniquement par un middleware de journalisation ou de diagnostic; voici ma méthode complète:


public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
    ILoggerFactory loggerFactory,
    IDatabaseInitializer databaseInitializer)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
    loggerFactory.AddNLog();

    // to serve up index.html
    app.UseDefaultFiles();
    app.UseStaticFiles();

    // http://www.talkingdotnet.com/aspnet-core-diagnostics-middleware-error-handling/
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();

    // CORS
    // https://docs.asp.net/en/latest/security/cors.html
    app.UseCors(builder =>
            builder.WithOrigins("http://localhost:4200", "http://www.myclientserver.com")
                .AllowAnyHeader()
                .AllowAnyMethod());

    app.UseOAuthValidation();
    app.UseOpenIddict();
    app.UseMvc();

    databaseInitializer.Seed().GetAwaiter().GetResult();
    env.ConfigureNLog("nlog.config");

    // swagger
    app.UseSwagger();
    app.UseSwaggerUi();
}

Le localhost CORS est utilisé pendant le développement et fait référence à une application Angular2 CLI. CORS fonctionne correctement localement, et mes applications clientes et API sont sur des ports différents sur le même hôte local. Il s'agit donc d'une "vraie" croix d'origine (je le remarque à cause des suggestions que j'ai trouvées ici: https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas : l'auteur de la publication remarque que l'en-tête CORS de la réponse est envoyé uniquement lorsque requis, c'est-à-dire dans les véritables environnements d'origine croisée).

En utilisant Fiddler, je peux accéder avec succès à l’API distante, mais je n’obtiens PAS d’en-tête Access-Control-Allow-Origin. Ainsi, lors de l'appel de l'API depuis le navigateur (via l'application client), la demande AJAX échoue, même si le serveur en renvoie 200. Exemple de demande Fiddler (succès):

GET http://mywebapisiteurl/api/values HTTP/1.1
User-Agent: Fiddler

réponse:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=prinapi.azurewebsites.net
Date: Thu, 01 Dec 2016 10:30:19 GMT

["value1","value2"]

Lorsque j'essaie d'accéder à l'API distante déployée sur Azure, l'application cliente échoue toujours avec sa demande AJAX avec erreur:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.myclientserver.com' is therefore not allowed access.

Voici un exemple de code client utilisant Angular2 (utilisant Plunker):

import {Component, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import { Http, Headers, Response } from '@angular/http';
import { HttpModule } from '@angular/http';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <button (click)="test()">test</button>
    </div>
  `,
})
export class App {
  name:string;
  constructor(private _http: Http) {
    this.name = 'Angular2'
  }
  public test() {
    this._http.get('http://theapisiteurlhere/api/values',
    {
        headers: new Headers({
          'Content-Type': 'application/json'
        })
    })
    .subscribe(
      (data: any) => {
        console.log(data);
      },
      error => {
        console.log(error);
      });
  }
}

@NgModule({
  imports: [ BrowserModule, HttpModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

En résumé, il semble que le serveur API ASPNET ne renvoie pas les en-têtes CORS attendus. Par conséquent, mon client basé sur un navigateur hébergé sur un serveur Origin différent échoue. Pourtant, la configuration de la SCRO semble être OK, du moins à en juger par la documentation citée ci-dessus; Je suis dans le véritable environnement d'origine croisée. et je place le middleware avant les autres. Peut-être me manque quelque chose d'évident, mais googler autour de ceci sont toutes les recommandations que j'ai trouvées. Un indice?

[~ # ~] met à jour [~ # ~]

En réponse à @Daniel J.G: la requête/réponse du violoniste a abouti:

GET http://theapiserver/api/values HTTP/1.1
User-Agent: Fiddler
Host: theapiserver
Origin: http://theappserver/apps/prin

et:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://theappserver/apps/prin
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=theapiserver
Date: Thu, 01 Dec 2016 14:15:21 GMT
Content-Length: 19

["value1","value2"]

La demande/réponse de Angular2 (Plunker) échoue à la place, comme indiqué. En inspectant le trafic réseau, je ne vois que la requête de contrôle en amont:

OPTIONS http://theapiserver/api/values HTTP/1.1
Host: theapiserver
Proxy-Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://run.plnkr.co
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://run.plnkr.co/h17wYofXGFuTy2Oh/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6

HTTP/1.1 204 No Content
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=theapiserver
Date: Thu, 01 Dec 2016 14:23:02 GMT

Après cela, la demande échoue et plus aucun trafic ne va au serveur. Le problème signalé est que Response to preflight request doesn't pass access control check, Encore une fois à cause du manque d'en-tête dans la réponse:

XMLHttpRequest cannot load http://theapiserver/api/values. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://run.plnkr.co' is therefore not allowed access.
31
Naftis

Voici la réponse à ma propre question, copiée à partir des commentaires: je n'avais pas remarqué que dans portail Azure, il existe une section CORS. Si je n'entre aucune origine autorisée à cet endroit, ma configuration basée sur du code semble être totalement hors de propos. Cela me semble étrange, car je suis obligé de dupliquer les URL ici, mais une fois j'ai ajouté * aux origines autorisées, cela a fonctionné.

9
Naftis

Ajouter la méthode .AllowAnyHeader () pourrait résoudre votre problème

app.UseCors(builder => builder.WithOrigins("http://localhost:4200")
                              .AllowAnyMethod()
                              .AllowAnyHeader());
4
Ashish Patel

Le message d'erreur est très erroné. J'obtenais la même erreur après avoir essayé d'ajouter une nouvelle table au DbContext. Angular ne donnait pas l'erreur non "Access-Control-Allow-Origin", mais Postman donnait une erreur de serveur interne 500. La méthode de connexion échouait lors de la tentative d'appel de _userManager.FindByEmailAsync (). J'espère que ceci aide quelqu'un d'autre.

0
Dumber_Texan2