IIS 中托管的 WebAPI 中的 CORS 问题
CORS problems in WebAPI hosted in IIS
我正在尝试实现一个应用程序,该应用程序使用 Taiseer Joudeh really awesome example 中演示的相同基于令牌的身份验证机制。
在我的应用程序中,我一直遇到 Cors 问题。在某些配置中,我会在 POST 获取令牌的预检(OPTIONS)请求中收到 500 错误,或者我可以获取令牌,但随后在预检请求中收到 404 错误,以获取实际的 GET 请求API 使用 Bearer 令牌调用。
一个区别是 Taiseer 的代码设置为托管在 IISExpress(或 Azure)中,而我的代码托管在本地 IIS 上(目前 运行 在 Windows 7 上)。
我凭直觉尝试在本地 IIS 下托管他的 API,但我发现了完全相同的问题。 (令牌的飞行前请求出现 500 错误,看起来实际 API 会正常工作)
从我读到的内容看来,这可能是 IIS 中的模块和处理程序与 WebApi 中的 Cors 实现之间存在一些冲突,但 Taiseer 的实现在托管在 Azure 中时有效,所以可能是版本不同IIS(我目前 运行 在 Windows 7 下)。
如何找出导致问题的原因?
这不是您使用的 IdentityServer,但可能是同一个问题。关于 IdentityServer 的 Github page,当 运行 在 IIS 下时,您必须为您的应用程序激活 RAMMFAR (runAllManagedModulesForAllRequests)。
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
问题的根源
令牌操作未托管在控制器中,而是内置在较低级别管道的某个位置。对该机制的唯一访问是通过扩展 OAuthAuthorizationServerProvider
的 class 中的覆盖方法 GrantResourceOwnerCredentials()
。 (在我们的例子中是 ApplicationOAuthProvider.cs
)。
GrantResourceOwnerCredentials()
确实有可用的上下文,但它不会作为 PreFlight 请求的一部分被调用,因此您无法为 CORS 插入适当的 PreFlight 响应 headers。
解决方案
我们最终确定了以下解决方案。我不是它的忠实粉丝,因为它迫使这些 headers 进入每个响应,但至少它有效。
解决方案是覆盖 Global.asax 中的 Application_PreSendRequestHeaders() 方法以插入适当的 headers.
Global.asax.cs
void Application_PreSendRequestHeaders(Object sender, EventArgs e)
{
var origin = Request.Headers.Get("Origin");
var validOrigins = ConfigurationManager.AppSettings["allowedCorsOrigins"].Split(',');
if(validOrigins.Any(o => o == origin))
{
Response.Headers.Set("Access-Control-Allow-Origin", origin);
Response.Headers.Set("Access-Control-Allow-Credentials", "true");
Response.Headers.Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, withcredentials, Prefer");
Response.Headers.Set("Access-Control-Expose-Headers", "Claims, *");
Response.Headers.Set("Access-Control-Max-Age", "600");
Response.Headers.Set("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
}
}
这需要以下 web.config 个条目:
web.config
<configuration>
<appSettings>
<add key="allowedCorsOrigins" value="http://www.allowedsite1.net,http://localhost:22687" />
<add key="allowedCorsMethods" value="get, post, put, delete, options, batch" />
<add key="allowedCorsHeaders" value="*" />
</appSettings>
...
</configuration>
循环搜索有效来源的原因是您无法使用允许的来源列表进行响应...
这解决了大部分问题,只有一个例外(如果我没记错的话是 PUT 和 DELETE 动词的问题)。这需要使用 web.config 的处理程序部分中的路径和动词删除 "ExtensionlessUrlHandler-Integrated-4.0" 和 re-adding。
web.config(第二次更改)
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="" />
</handlers>
....
</system.webServer>
与 CORS 相关的有用链接
我遇到了同样的问题,我按照 Tom hall 先生的建议做了一切。但仍然 chrome 报告没有 Access-control-allow-origin header 存在..在用 fidler 检查后我意识到我的请求通过代理服务器并且我的代理服务器正在处理预检选项请求..
所以在 "internet options" 我删除了代理服务器并发现一切正常 工作 ...!!!
我正在尝试实现一个应用程序,该应用程序使用 Taiseer Joudeh really awesome example 中演示的相同基于令牌的身份验证机制。
在我的应用程序中,我一直遇到 Cors 问题。在某些配置中,我会在 POST 获取令牌的预检(OPTIONS)请求中收到 500 错误,或者我可以获取令牌,但随后在预检请求中收到 404 错误,以获取实际的 GET 请求API 使用 Bearer 令牌调用。
一个区别是 Taiseer 的代码设置为托管在 IISExpress(或 Azure)中,而我的代码托管在本地 IIS 上(目前 运行 在 Windows 7 上)。
我凭直觉尝试在本地 IIS 下托管他的 API,但我发现了完全相同的问题。 (令牌的飞行前请求出现 500 错误,看起来实际 API 会正常工作)
从我读到的内容看来,这可能是 IIS 中的模块和处理程序与 WebApi 中的 Cors 实现之间存在一些冲突,但 Taiseer 的实现在托管在 Azure 中时有效,所以可能是版本不同IIS(我目前 运行 在 Windows 7 下)。
如何找出导致问题的原因?
这不是您使用的 IdentityServer,但可能是同一个问题。关于 IdentityServer 的 Github page,当 运行 在 IIS 下时,您必须为您的应用程序激活 RAMMFAR (runAllManagedModulesForAllRequests)。
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
问题的根源
令牌操作未托管在控制器中,而是内置在较低级别管道的某个位置。对该机制的唯一访问是通过扩展 OAuthAuthorizationServerProvider
的 class 中的覆盖方法 GrantResourceOwnerCredentials()
。 (在我们的例子中是 ApplicationOAuthProvider.cs
)。
GrantResourceOwnerCredentials()
确实有可用的上下文,但它不会作为 PreFlight 请求的一部分被调用,因此您无法为 CORS 插入适当的 PreFlight 响应 headers。
解决方案
我们最终确定了以下解决方案。我不是它的忠实粉丝,因为它迫使这些 headers 进入每个响应,但至少它有效。
解决方案是覆盖 Global.asax 中的 Application_PreSendRequestHeaders() 方法以插入适当的 headers.
Global.asax.cs
void Application_PreSendRequestHeaders(Object sender, EventArgs e)
{
var origin = Request.Headers.Get("Origin");
var validOrigins = ConfigurationManager.AppSettings["allowedCorsOrigins"].Split(',');
if(validOrigins.Any(o => o == origin))
{
Response.Headers.Set("Access-Control-Allow-Origin", origin);
Response.Headers.Set("Access-Control-Allow-Credentials", "true");
Response.Headers.Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, withcredentials, Prefer");
Response.Headers.Set("Access-Control-Expose-Headers", "Claims, *");
Response.Headers.Set("Access-Control-Max-Age", "600");
Response.Headers.Set("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
}
}
这需要以下 web.config 个条目:
web.config
<configuration>
<appSettings>
<add key="allowedCorsOrigins" value="http://www.allowedsite1.net,http://localhost:22687" />
<add key="allowedCorsMethods" value="get, post, put, delete, options, batch" />
<add key="allowedCorsHeaders" value="*" />
</appSettings>
...
</configuration>
循环搜索有效来源的原因是您无法使用允许的来源列表进行响应...
这解决了大部分问题,只有一个例外(如果我没记错的话是 PUT 和 DELETE 动词的问题)。这需要使用 web.config 的处理程序部分中的路径和动词删除 "ExtensionlessUrlHandler-Integrated-4.0" 和 re-adding。
web.config(第二次更改)
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="" />
</handlers>
....
</system.webServer>
与 CORS 相关的有用链接
我遇到了同样的问题,我按照 Tom hall 先生的建议做了一切。但仍然 chrome 报告没有 Access-control-allow-origin header 存在..在用 fidler 检查后我意识到我的请求通过代理服务器并且我的代理服务器正在处理预检选项请求..
所以在 "internet options" 我删除了代理服务器并发现一切正常 工作 ...!!!