Asp.net web api 为Web Api 2和OWIN令牌身份验证启用CORS

Asp.net web api 为Web Api 2和OWIN令牌身份验证启用CORS,asp.net-web-api,asp.net-mvc-5,cors,asp.net-web-api2,owin,Asp.net Web Api,Asp.net Mvc 5,Cors,Asp.net Web Api2,Owin,我有一个ASP.NET MVC 5 webproject(localhost:81),它使用Knockoutjs调用我的WebApi 2项目(localhost:82)中的函数,以实现我启用CORS的两个项目之间的通信。直到我尝试对WebApi实现OWIN令牌身份验证之前,一切都正常 要在WebApi上使用/token端点,我还需要在端点上启用CORS,但经过数小时的尝试和搜索解决方案后,它现在仍在工作,api/token仍然会导致: XMLHttpRequest cannot load htt

我有一个ASP.NET MVC 5 webproject(localhost:81),它使用Knockoutjs调用我的WebApi 2项目(localhost:82)中的函数,以实现我启用CORS的两个项目之间的通信。直到我尝试对WebApi实现OWIN令牌身份验证之前,一切都正常

要在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配置(IAppBuilder应用程序)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
TokenConfig.ConfigureOAuth(应用程序);
...
}
令牌配置

publicstaticvoid配置OAuth(IAppBuilder应用程序)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext(AppUserManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions=新的OAuthAuthorizationServerOptions()
{
AllowInsecureHttp=true,
TokenEndpointPath=新路径字符串(“/token”),
AccessTokenExpireTimeSpan=TimeSpan.FromDays(1),
Provider=新的SimpleAuthorizationServerProvider()
};
使用OAuthAuthorizationServer(OAuthServerOptions);
使用OAuthBeareAuthentication(新的OAuthBeareAuthenticationOptions());
}
授权提供者

public override异步任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext)
{
context.OwinContext.Response.Headers.Add(“访问控制允许来源”,新[]{“*”});
var appUserManager=context.OwinContext.GetUserManager();
IdentityUser user=wait-appUserManager.FindAsync(context.UserName,context.Password);
if(user==null)
{
SetError(“无效的授权”,“用户名或密码不正确”);
返回;
}
…索赔
}
标识配置

公共静态AppUserManager创建(IdentityFactoryOptions选项,IOwinContext上下文) { //试图再次启用,但未成功。 //Add(“访问控制允许来源”,新[]{“*”}); var manager=newappusermanager(newuserstore(context.Get()); ... var dataProtectionProvider=options.dataProtectionProvider; if(dataProtectionProvider!=null) { manager.UserTokenProvider= 新的DataProtectorTokenProvider(dataProtectionProvider.Create(“ASP.NET标识”); } 退货经理; } 编辑:

1。重要注意事项是,直接打开端点(localhost:82/token)是有效的。


2。从webproject调用Api(localhost:82/Api/)也可以,因此CORS已为WebApi启用。

我知道您的问题已在评论中得到解决,但我认为了解问题的原因以及如何解决这整类问题很重要

查看您的代码,我可以看到您正在为令牌端点多次设置
访问控制允许原点
头:

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
和内部
GrantResourceOwnerCredentials
方法:

context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 
从总体上看,这本身就是一个问题,因为:

如果响应包含零个或多个Access Control Allow Origin标头值,则返回fail并终止此算法

在您的场景中,框架将设置此头两次,并且了解必须如何实现CORS,这将导致在某些情况下删除头(可能与客户端相关)

以下问题的答案也证实了这一点:

因此,在调用
ConfigureOAuth
之后,将调用移动到
app.UseCors
,只允许设置一次CORS头(因为owin管道在OAuth中间件处中断,并且永远不会到达
令牌
端点的Microsoft CORS中间件),并使Ajax调用工作


为了获得更好的全局解决方案,您可以尝试在OAuth中间件调用之前再次放置
app.UseCors
,并删除第二个
Access Control Allow Origin
insertion in
GrantResourceOwnerCredentials

遵循以下步骤,您的API将正常工作:

  • 从API中删除
    config.EnableCors(),[EnableCors(头:“*”…)]
    等任何代码
  • 转到startup.cs并在第行下方添加

    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    
  • 以前

        ConfigureAuth(app);
    
    Uou还需要安装Microsoft.owin.cors软件包才能使用此功能

    在不使用app.UseCors()的情况下解决问题 我也有同样的问题。我使用带有Axiis的Vue.Js客户端访问我的REST-API。在我的Owin Api服务器上,由于与其他第三方组件的版本冲突,我无法添加Microsoft.Owin.Cors
    nuget。所以我无法使用app.UseCors()方法,但我使用中间件管道解决了这个问题

    private-IDisposable\u-webServer=null;
    public void Start(客户端凭据)
    {
    ...
    _webServer=WebApp.Start(BaseAddress,(x)=>Configuration(x));
    ...
    }
    公共无效配置(IAppBuilder应用程序)
    {
    ...
    //添加了中间件而不是app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    app.Use();
    app.UseWebApi(配置);
    ...
    }
    公共类MyOwinMiddleware:OwinMiddleware
    {
    公共MyOwinMiddleware(OwinMiddleware下一步):
    基地(下一个)
    { }
    公共重写异步任务调用(IOwinContext上下文)
    {
    var-request=context.request;
    var-response=context.response;
    响应。OnSendingHeader(状态=>
    {
    var resp=(IOwinResponse)状态;
    //如果没有此标题->客户端应用程序将被阻止使用此api中的数据
    如果(!resp.Headers.ContainsKey(“访问控制允许源”))