![](/img/trans.png)
[英]How to enable windows authentication in conjunction with Owin token authentication in web api?
[英]Enable CORS for Web Api 2 and OWIN token authentication
我有一個 ASP.NET MVC 5 web 項目 (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。
我知道您的問題已在評論中解決,但我相信了解導致問題的原因以及如何解決這一整類問題很重要。
查看您的代碼,我可以看到您不止一次為 Token 端點設置Access-Control-Allow-Origin
標頭:
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.UseCors
調用后ConfigureOAuth
讓您的CORS頭一次只能設置(因為owin管道在OAuth的中間件中斷,並且永遠不會達到對微軟CORS中間件Token
端點)和品牌您的 Ajax 調用正常工作。
為了更好的和全球性的解決方案,你可以嘗試再次把app.UseCors
的OAuth的中間件調用之前,取出第二個Access-Control-Allow-Origin
內側插入GrantResourceOwnerCredentials
。
按照以下步驟操作,您的 API 將正常工作:
config.EnableCors(), [EnableCors(header:"*"....)]
。轉到 startup.cs 並添加以下行
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
之前
ConfigureAuth(app);
您還需要安裝 Microsoft.owin.cors 包才能使用此功能
我有同樣的問題。 我用了一個Vue.Js客戶端axois跨團訪問我的REST的API。 在我的 Owin-Api-Server 上,由於與其他 3rd 方組件的版本沖突,我無法添加 Microsoft.Owin.Cors nuget。 所以我不能使用 app.UseCors()方法,但我通過使用中間件管道解決了它。
private IDisposable _webServer = null;
public void Start(ClientCredentials credentials)
{
...
_webServer = WebApp.Start(BaseAddress, (x) => Configuration(x));
...
}
public void Configuration(IAppBuilder app)
{
...
// added middleware insted of app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.Use<MyOwinMiddleware>();
app.UseWebApi(config);
...
}
public class MyOwinMiddleware : OwinMiddleware
{
public MyOwinMiddleware(OwinMiddleware next) :
base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
var request = context.Request;
var response = context.Response;
response.OnSendingHeaders(state =>
{
var resp = (IOwinResponse)state;
// without this headers -> client apps will be blocked to consume data from this api
if (!resp.Headers.ContainsKey("Access-Control-Allow-Origin"))
resp.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
if (!resp.Headers.ContainsKey("Access-Control-Allow-Headers"))
resp.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });
if (!resp.Headers.ContainsKey("Access-Control-Allow-Methods"))
resp.Headers.Add("Access-Control-Allow-Methods", new[] { "*" });
// by default owin is blocking options not from same origin with MethodNotAllowed
if (resp.StatusCode == (int)HttpStatusCode.MethodNotAllowed &&
HttpMethod.Options == new HttpMethod(request.Method))
{
resp.StatusCode = (int)HttpStatusCode.OK;
resp.ReasonPhrase = HttpStatusCode.OK.ToString();
}
}, response);
await Next.Invoke(context);
}
}
所以我創建了自己的中間件並操縱了響應。 GET 調用只需要 Access-Control-Allow 標頭,而對於 OPTIONS 調用,我還需要操作 StatusCode,因為 axois.post() 在發送 POST 之前首先使用 OPTIONS-method 調用。 如果 OPTIONS 返回 StatusCode 405,則永遠不會發送 POST。
這解決了我的問題。 也許這也可以幫助某人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.