Ich schwöre, das ist so oft passiert, dass ich tatsächlich hasse CORS. Ich habe gerade meine Anwendung in zwei aufgeteilt, so dass man nur die API-Seite der Dinge behandelt und die andere behandelt die clientseitigen Sachen. Ich habe das schon mal gemacht, so dass ich wusste, dass ich sicher CORS zu machen brauchte aktiviert und erlaubte alle, so dass ich dies bis in WebApiConfig.csGefürchtete CORS Problem mit WebAPI und Token
public static void Register(HttpConfiguration config)
{
// Enable CORS
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// Web API configuration and services
var formatters = config.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var serializerSettings = jsonFormatter.SerializerSettings;
// Remove XML formatting
formatters.Remove(config.Formatters.XmlFormatter);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
// Configure our JSON output
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
serializerSettings.Formatting = Formatting.Indented;
serializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
serializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
// Configure the API route
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Wie Sie sehen können, meine erste Linie Aktiviert das CORS, so sollte es funktionieren. Wenn ich meine Client-Anwendung öffnen und die API abfragen, funktioniert es tatsächlich (ohne die EnableCors bekomme ich den erwarteten CORS-Fehler. Das Problem ist mein /Token bekommt immer noch einen CORS-Fehler. Jetzt bin ich mir bewusst, dass/Token Endpunkt ist nicht Teil der WebAPI, so dass ich meinen eigenen OAuthProvider (was muß mich darauf hinweisen in anderen Orten ganz gut verwendet wird) und das sieht wie folgt aus:
public class OAuthProvider<TUser> : OAuthAuthorizationServerProvider
where TUser : class, IUser
{
private readonly string publicClientId;
private readonly UserService<TUser> userService;
public OAuthProvider(string publicClientId, UserService<TUser> userService)
{
if (publicClientId == null)
throw new ArgumentNullException("publicClientId");
if (userService == null)
throw new ArgumentNullException("userService");
this.publicClientId = publicClientId;
this.userService = userService;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var user = await this.userService.FindByUserNameAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var oAuthIdentity = this.userService.CreateIdentity(user, context.Options.AuthenticationType);
var cookiesIdentity = this.userService.CreateIdentity(user, CookieAuthenticationDefaults.AuthenticationType);
var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
context.AdditionalResponseParameters.Add(property.Key, property.Value);
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == this.publicClientId)
{
var redirectUri = new Uri(context.RedirectUri);
var expectedRootUri = new Uri(context.Request.Uri, redirectUri.PathAndQuery);
if (expectedRootUri.AbsoluteUri == redirectUri.AbsoluteUri)
context.Validated();
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
wie Sie sehen können, in den GrantResourceOwnerCredentials Methode Ich erlaube CORS Zugriff auf alles wieder. Dies sollte für alle Anfragen an/Token funktionieren, aber es nicht. Wenn ich versuche, mich von meinem Client anzumelden a Anwendung bekomme ich einen CORS-Fehler. Chrome zeigt dies:
XMLHttpRequest cannot load http://localhost:62605/token . Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ' http://localhost:50098 ' is therefore not allowed access. The response had HTTP status code 400.
und Firefox zeigt dies:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token . (Reason: CORS header 'Access-Control-Allow-Origin' missing). Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token . (Reason: CORS request failed).
Zu Testzwecken habe ich beschlossen, Fiedler zu verwenden, um zu sehen, ob ich etwas sehen konnte, anderes, das mir einen Anhaltspunkt geben könnte, was es passiert. Wenn ich versuche, um sich einzuloggen, zeigt Fiddler einen Antwortcode 400, und wenn ich an der rohen Antwort aussehen kann ich den Fehler sehen:
{"error":"unsupported_grant_type"}
die seltsam ist, weil die Daten, die ich hat sende nicht geändert und arbeitete gut vor dem Split. Ich entschied mich, den Composer auf fiddler zu verwenden und replizierte, wie die POST-Anfrage aussehen sollte. Wenn ich es ausführe, funktioniert es gut und ich bekomme einen Antwortcode von 200.
Hat jemand eine Idee, warum das passieren könnte?
Update 1
nur als Referenz, die Anfrage von meinem Client-Anwendung wie folgt aussieht:
OPTIONS http://localhost:62605/token HTTP/1.1
Host: localhost:62605
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:50098
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:50098/account/signin
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
vom Komponisten, sieht es wie folgt aus:
POST http://localhost:62605/token HTTP/1.1
User-Agent: Fiddler
Content-Type: 'application/x-www-form-urlencoded'
Host: localhost:62605
Content-Length: 67
grant_type=password&userName=foo&password=bar
Pflege um zu erarbeiten? – user210757
Wie sieht Ihr Interceptor jetzt aus? – RandomUs1r