从 Angular2 从 Web API2 获取令牌会导致 CORS 问题或 null



我正在尝试登录(Angular2 - 客户端和Web API 2 - 在服务器上(。

我收到一个

选项 http://localhost:48604/Token 400(错误请求(

其次

无法加载 http://localhost:48604/Token:对预检请求的响应未通过访问控制检查:请求的资源上不存在"访问控制允许源"标头。因此,不允许访问源"http://localhost:4200"。响应具有 HTTP 状态代码 400。

而其他请求不会因 CORS 问题而失败,因为我已在WebApiConfig 中全局启用了 CORS.cs

网页应用接口:

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));
EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

}
}

MyStartup.Auth.cs

public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
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);
// ... Code for third-part logins omitted for brevity ...
}
}

我的角度服务:

export class AuthService {
rootUrl = 'http://localhost:48604';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
constructor(private httpClient: HttpClient) {
}
logIn(loginData): Observable<any> {
const data = 'grant_type=password&username=' + loginData.username + '&password=' + loginData.password;
return this.httpClient.post(this.rootUrl + '/Token', data, this.httpOptions);
}
}

据我了解,在/Token之后,请求应该重定向到api/Account/ExternalLogin,但永远不会到达这个控制器方法。

然后我找到了一个帖子,他们说你需要在ApplicationOAuthProvider类中覆盖MatchEndpoint方法,我做到了:

public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization"});
context.RequestCompleted();
return Task.FromResult(0);
}
return base.MatchEndpoint(context);
}

在我的登录组件中:

this.authService.logIn(loginData).subscribe(
(data) => {
console.log(data);
//sessionStorage.setItem('tokenKey', token);
//console.log('sessionStorage.getItem: ' + sessionStorage.getItem('tokenKey'));
},
);

现在我对 POST 请求的响应是 200 OK,但控制台仍然说:

无法加载 http://localhost:48604/Token:请求的资源上不存在"访问控制允许源"标头。因此,不允许访问源"http://localhost:4200"。

然后我添加一个 if 对于 POST 方法,我还添加了所需的标头:

public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin",
new[] {"http://localhost:4200"});
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] {"authorization"});
context.RequestCompleted();
return Task.FromResult(0);
}
if (context.IsTokenEndpoint && context.Request.Method == "POST")
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization", "Content-Type" });
context.RequestCompleted();
return Task.FromResult(0);
}
return base.MatchEndpoint(context);
}

现在 POST 方法将在响应中添加标头但我得到空而不是令牌。

好的,问题解决了。如本视频所述(31:00 分钟(

因此 ASP.NET 标识使用 OWIN,它需要在Startup.cs文件的ConfigureAuth方法中启用 CORS

public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.UseCors(CorsOptions.AllowAll);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
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);
// ... Code for third-part logins omitted for brevity ...
}
}

现在要做到这一点,我们需要将 NuGet 包安装到项目中:

Install-Package Microsoft.Owin.Cors

而且我不再需要在 WebApiConfig 文件中启用 CORS:

EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(cors);

WebApi配置文件

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));
// EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
// config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

}
}

我也不需要像我之前发布的那样重写 MatchEndpoint 方法。

现在,当我发出登录请求时,我会收到带有令牌的响应:

Request URL: http://localhost:48604/Token

我看到在响应标题中添加了:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4200

当我向另一个 API 控制器发出请求时,请说:

Request URL: http://localhost:48604/api/UpdateUsrRole

我首先在请求方法中看到:选项 添加了以下标头:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Origin: http://localhost:4200

然后当请求方法:PUT 触发时 添加了以下标头:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4200

就是这样。

您可以将 proxy.config.json 文件添加到您的 angular 应用程序以允许 CORS,因为 Angular 在端口 4200 上运行,而您的后端可能还有其他东西。

https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md

然后通过ng serve --proxy-config proxy.config.json

这将重写对指定端口等的任何请求(您的后端(

如果你在 1 个包中构建你的应用程序,那么你不应该有 cors 问题。 ** 构建角度,然后添加到后端的静态资源中**

最新更新