我有一个使用Windows身份验证运行的WebAPI 2 REST服务。它与网站分开托管,因此我使用ASP.NET CORS NuGet包启用了CORS。我的客户端站点正在使用AngularJS。
到目前为止,我所经历的是:
我被困的地方 - 我的Angular预检电话不包括凭据。根据{{3}},这是设计的,因为OPTIONS请求被设计为匿名的。但是,Windows身份验证使用401停止请求。
我已经尝试将[AllowAnonymous]属性放在我的MessageHandler上。在我的开发计算机上,它可以工作 - OPTIONS动词不需要身份验证,但其他动词可以。但是,当我构建并部署到测试服务器时,我将继续在我的OPTIONS请求中获得401。
使用Windows身份验证时,是否可以在MessageHandler上应用[AllowAnonymous]?如果是的话,有关如何做的任何指导?或者这是一个错误的兔子洞,我应该看一个不同的方法?
更新: 通过在IIS中的站点上设置Windows身份验证和匿名身份验证,我能够使其工作。这导致一切都允许匿名,所以我添加了一个全局的Authorize过滤器,同时在我的MessageHandler上保留了AllowAnonymous。
然而,这感觉就像一个黑客...我一直都明白只应该使用一种身份验证方法(不混合)。如果有人有更好的方法,我很高兴听到它。
答案 0 :(得分:13)
我使用HttpListener进行自托管,以下解决方案为我工作:
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
var listener = appBuilder.Properties["System.Net.HttpListener"] as HttpListener;
if (listener != null)
{
listener.AuthenticationSchemeSelectorDelegate = (request) => {
if (String.Compare(request.HttpMethod, "OPTIONS", true) == 0)
{
return AuthenticationSchemes.Anonymous;
}
else
{
return AuthenticationSchemes.IntegratedWindowsAuthentication;
}};
}
答案 1 :(得分:6)
我一直在努力使CORS请求在以下限制内工作(非常类似于OP的那些):
我的最终配置如下:
web.config - 允许未经身份验证的(匿名)预检请求(OPTIONS)
<system.web>
<authentication mode="Windows" />
<authorization>
<allow verbs="OPTIONS" users="*"/>
<deny users="?" />
</authorization>
</system.web>
global.asax.cs - 正确回复标题,允许其他域的来电者接收数据
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.Request.HttpMethod == "OPTIONS")
{
if (Context.Request.Headers["Origin"] != null)
Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
Response.End();
}
}
启用CORS
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// all requests are enabled in this example. SupportsCredentials must be here to allow authenticated requests
var corsAttr = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
config.EnableCors(corsAttr);
}
}
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
答案 2 :(得分:2)
我以非常类似的方式解决了它,但有一些细节并专注于oData服务
我没有禁用IIS中的匿名身份验证,因为我需要POST请求
我已在Global.aspx中添加(在MaxDataServiceVersion
中添加Access-Control-Allow-Headers
)与上面相同的代码
protected void Application_BeginRequest(object sender, EventArgs e)
{
if ((Context.Request.Path.Contains("api/") || Context.Request.Path.Contains("odata/")) && Context.Request.HttpMethod == "OPTIONS")
{
Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,MaxDataServiceVersion");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
Context.Response.End();
}
}
和WebAPIConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
和AngularJS调用
$http({
method: 'POST',
url: 'http://XX.XXX.XXX.XX/oData/myoDataWS.svc/entityName',
withCredentials: true,
headers: {
'Content-Type': 'application/json;odata=verbose',
'Accept': 'application/json;odata=light;q=1,application/json;odata=verbose;q=0.5',
'MaxDataServiceVersion': '3.0'
},
data: {
'@odata.type':'entityName',
'field1': 1560,
'field2': 24,
'field3': 'sjhdjshdjsd',
'field4':'wewewew',
'field5':'ewewewe',
'lastModifiedDate':'2015-10-26T11:45:00',
'field6':'1359',
'field7':'5'
}
});
答案 3 :(得分:2)
这是一个更简单的解决方案 - 几行代码允许所有“OPTIONS”请求有效地模拟应用程序池帐户。您可以保持Anonymous关闭,并按照常规做法配置CORS策略,但随后将以下内容添加到您的global.asax.cs中:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.Request.HttpMethod == "OPTIONS" && Context.User == null)
{
Context.User = System.Security.Principal.WindowsPrincipal.Current;
}
}
答案 4 :(得分:0)
戴夫,
在使用CORS软件包之后,这就是它对我有用的原因:[EnableCors(起源:“”,标题:“”,方法:“*”, SupportsCredentials =真强>)]
我必须启用SupportsCredentials = true。起源,标题和方法都设置为“*”
答案 5 :(得分:0)
如果您不需要,请在IIS中禁用匿名身份验证。
在全局的asax中添加:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if ((Context.Request.Path.Contains("api/") || Context.Request.Path.Contains("odata/")) && Context.Request.HttpMethod == "OPTIONS")
{
Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
Context.Response.End();
}
}
确保在启用cors的位置启用凭据,例如:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
如您所见,我全局启用CORS并使用应用程序BeginRequest挂钩我验证api(Web Api)和odata请求(如果您使用它)的所有OPTIONS请求。
这适用于所有浏览器,在客户端,请记得添加xhrFiled withCredentials,如下所示。
$.ajax({
type : method,
url : apiUrl,
dataType : "json",
xhrFields: {
withCredentials: true
},
async : true,
crossDomain : true,
contentType : "application/json",
data: data ? JSON.stringify(data) : ''
}).....
我试图找到另一个避免使用钩子的解决方案,但直到现在还没有成功, 我会使用web.config配置执行以下操作: 警告下面的配置是否工作!
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
<authorization>
<deny verbs="GET,PUT,POST" users="?" />
<allow verbs="OPTIONS" users="?"/>
</authorization>
</system.web>
<location path="api">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
答案 6 :(得分:0)
我在网上找到的其他解决方案对我来说没有用,或者看起来太苛刻了;最后,我提出了一个更简单,更有效的解决方案:
<强>的web.config:强>
<system.web>
...
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
</system.web>
项目属性:
Windows Authentication
Anonymous Authentication
设置CORS:
[assembly: OwinStartup(typeof(Startup))]
namespace MyWebsite
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
这需要在NUget上可用的Microsoft.Owin.Cors程序集。
角度初始化:
$httpProvider.defaults.withCredentials = true;
答案 7 :(得分:0)
这是我的解决方案。
<强>的Global.asax * 强>
protected void Application_BeginRequest(object sender, EventArgs e)
{
if(!ListOfAuthorizedOrigins.Contains(Context.Request.Headers["Origin"])) return;
if (Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
HttpContext.Current.Response.StatusCode = 200;
HttpContext.Current.Response.End();
}
if (Request.Headers.AllKeys.Contains("Origin"))
{
HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
}
}
答案 8 :(得分:0)
在我们的情况下:
我们发现解决方案在其他地方:
在 Web.Config 中,我们要做的就是添加 runAllManagedModulesForAllRequests = true
<modules runAllManagedModulesForAllRequests="true">
我们通过研究为什么未触发 Application_BeginRequest 的解决方案来结束了该解决方案。
我们拥有的其他配置:
在 Web.Config
中 <authentication mode="Windows" />
<authorization>
<allow verbs="OPTIONS" users="*" />
<deny users="?"/>
</authorization>
在 WebApiConfig
中 private static string GetAllowedOrigins()
{
return ConfigurationManager.AppSettings["CorsOriginsKey"];
}
public static void Register(HttpConfiguration config)
{
//set cors origins
string origins = GetAllowedOrigins();
var cors = new EnableCorsAttribute(origins, "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
BTW“ *” cors来源与Windows身份验证不兼容/ SupportCredentials = true