Asp.net-Web-Api

為 Web Api 2 和 OWIN 令牌身份驗證啟用 CORS

  • March 29, 2016

我有一個 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 Configuration(IAppBuilder app)
{
   app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
   TokenConfig.ConfigureOAuth(app);
   ...
}

令牌配置

public static void ConfigureOAuth(IAppBuilder app)
{
   app.CreatePerOwinContext(ApplicationDbContext.Create);
   app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);

   OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
   {
       AllowInsecureHttp = true,
       TokenEndpointPath = new PathString("/token"),
       AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
       Provider = new SimpleAuthorizationServerProvider()
   };

   app.UseOAuthAuthorizationServer(OAuthServerOptions);
   app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}

授權提供者

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
   context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

   var appUserManager = context.OwinContext.GetUserManager<AppUserManager>();
   IdentityUser user = await appUserManager.FindAsync(context.UserName, context.Password);

   if (user == null)
   {
       context.SetError("invalid_grant", "The user name or password is incorrect.");
       return;
   }
   ... claims
}

身份配置

public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
   // Tried to enable it again without success. 
   //context.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});
   
   var manager = new AppUserManager(new UserStore<AppUser>(context.Get<ApplicationDbContect>()));
       
   ...

   var dataProtectionProvider = options.DataProtectionProvider;
   if (dataProtectionProvider != null)
   {
       manager.UserTokenProvider =
               new DataProtectorTokenProvider<AppUser>(dataProtectionProvider.Create("ASP.NET Identity"));
   }
   return manager;
}

編輯:

1. 重要說明是直接打開端點(localhost:82/token)可以。

2. 從 webproject 呼叫 Api (localhost:82/api/..) 也可以,因此為 WebApi 啟用了 CORS。

我知道您的問題已在評論中解決,但我認為了解導致問題的原因以及如何解決這一類問題很重要。

查看您的程式碼,我可以看到您Access-Control-Allow-Origin為 Token 端點多次設置標頭:

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

和內部GrantResourceOwnerCredentials方法:

context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

CORS 規範來看,這本身就是一個問題,因為:

如果響應包含零個或多個 Access-Control-Allow-Origin 標頭值,則返回失敗並終止此算法。

在您的場景中,框架設置此標頭兩次,並了解必須如何實現 CORS,這將導致在某些情況下刪除標頭(可能與客戶端相關)。

以下問題答案也證實了這一點:Duplicate Access-Control-Allow-Origin: * 導致 COR 錯誤?

出於這個原因,將呼叫移至呼叫app.UseCorsConfigureOAuth允許您的 CORS 標頭僅設置一次(因為 owin 管道在 OAuth 中間件處中斷,並且永遠不會到達Token端點的 Microsoft CORS 中間件)並使您的 Ajax 呼叫正常工作。

為了獲得更好的全域解決方案,您可以嘗試app.UseCors在 OAuth 中間件呼叫之前再次放置,並刪除內部的第二個Access-Control-Allow-Origin插入GrantResourceOwnerCredentials

引用自:https://stackoverflow.com/questions/36285253