IIS中托管的WebAPI中的CORS问题 [英] CORS problems in WebAPI hosted in IIS

查看:134
本文介绍了IIS中托管的WebAPI中的CORS问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用此

I'm trying to implement an application that uses the same Token Based Authentication mechanism demonstrated in this really awesome example by Taiseer Joudeh.

在我的应用程序中,我不断遇到Cors问题.在某些配置中,我将在POST的预检(OPTIONS)请求上收到500错误,或者我可以获取令牌,但是在GET请求到实际API调用的预检请求中却收到404错误,不记名令牌.

In my application I kept encountering Cors problems. In some configurations I would get a 500 error on the Preflight (OPTIONS) request for the POST to get the token or I could get the token but then get a 404 error on the preflight request for the GET request to the actual API call with the Bearer token.

一个区别是,Taiseer的代码已设置为在IISExpress(或Azure)中托管,而我的代码则在本地IIS(目前在Windows 7上运行)中托管.

One difference was that Taiseer's code was setup to host in IISExpress (or Azure) and mine is hosted on Local IIS (running on Windows 7 at the moment).

直觉上,我尝试在本地IIS下托管他的API,但我发现了完全相同的问题.(在预检令牌请求时出现500错误,看起来实际的API可以正常工作)

On a hunch I tried hosting his API under Local IIS and I found the exact same problem. (500 error on the preflight request for the token and it looks like the actual API will work properly)

从我一直看过的内容来看,这似乎可能是IIS中的模块和处理程序与WebApi中的Cors实现之间的某些冲突,但是Taiseer的实现在托管于Azure时有效,因此IIS版本可能有所不同(我目前在Windows 7下运行).

From what I've been reading it seems like this may be some conflict between the modules and handlers in IIS and the Cors implementation in WebApi but Taiseer's implementation works when hosted in Azure so perhaps it is a difference in the version of IIS (I'm currently running under Windows 7).

如何找出导致问题的原因?

How can I sort out what is causing the problem?

推荐答案

问题的根源

令牌操作不是托管在控制器中,而是内置在较低级管道中的某个位置.对该机制的唯一访问权是通过扩展 OAuthAuthorizationServerProvider 的类中的覆盖方法 GrantResourceOwnerCredentials().(在我们的例子中是 ApplicationOAuthProvider.cs ).

The root of the problem

The Token action is not hosted in a controller but is instead built in somewhere in the lower level plumbing. The only access to the mechanism is through the override method GrantResourceOwnerCredentials() in the class that extends OAuthAuthorizationServerProvider. (In our case is ApplicationOAuthProvider.cs).

GrantResourceOwnerCredentials()确实具有可用的上下文,但未作为PreFlight请求的一部分进行调用,因此您无法为CORS插入适当的PreFlight响应标头.

GrantResourceOwnerCredentials() does have the context available but it is not called as part of the PreFlight request so you have no way to insert the appropriate PreFlight response headers for CORS.

我们最终决定采用以下解决方案.我不是它的忠实拥护者,因为它会在所有响应中强制使用这些标头,但至少可以奏效.

We eventually settled on the following solution. I'm not a big fan of it because it forces these headers into every response but at least it works.

解决方案是在Global.asax中重写Application_PreSendRequestHeaders()方法以插入适当的标头.

The solution was to override Application_PreSendRequestHeaders() method in Global.asax to insert the appropriate headers.

    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条目:

This requires the following web.config entries:

<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>

循环搜索有效原点的原因是您无法使用允许的原点列表进行响应...

The reason for the loop to search for the valid origins is that you can't respond with a list of allowed origins...

这可以解决大多数问题,只有一个例外(如果我没记错的话,是PUT和DELETE动词的问题).这需要删除"ExtensionlessUrlHandler-Integrated-4.0",并在web.config的处理程序部分中将其与路径和动词一起重新添加.

This solved most of the problems with one exception (If I recall correctly was problems with PUT and DELETE verbs). This required removing the "ExtensionlessUrlHandler-Integrated-4.0" and re-adding it with a path and verb in the handlers section of the 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相关的有用链接

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆