Asp.Net MVC WebApi CORS 请求失败 - 没有建议的解决方案影响结果

Posted

技术标签:

【中文标题】Asp.Net MVC WebApi CORS 请求失败 - 没有建议的解决方案影响结果【英文标题】:Asp.Net MVC WebApi CORS Request fails - no proposed solutions affecting the outcome 【发布时间】:2020-02-19 00:14:23 【问题描述】:

我在 localhost:59569 (SiteApi) 上有一个 Asp.Net NVC5 Web 应用程序(在 Visual Studio 2017 下运行)。我在 localhost:61527 (SiteClient) 上有第二个网站(也在 Visual Studio 2017 下运行),其中一个页面一旦加载就会对 SiteApi 进行以下 api 调用:

$http(
    url: 'http://localhost:59569/api/V2/' + alias,
    method: 'POST',
    data: pm,
    xhrFields:  withCredentials: true ,
    headers:  'Content-Type': 'application/json; charset=utf-8' 
    )
    .then(th, ex);

注意:我已经使用 Microsoft IE、Microsoft Edge 和 Chrome 尝试了使用和不使用 xhrFields + withCredentials 信息。

返回 SiteApi,生成的 OPTIONS 预检调用被 Global.asax 中的以下代码截获,该代码完全按照编写的方式执行,当对 OPTIONS 的入站调用触发它时,我可以跟踪 if 语句。

protected void Application_BeginRequest()

    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    
        Response.Clear();
        Response.Headers.Add("Access-Control-Allow-Origin", "*");
        Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, Session");
        Response.Flush();
        Response.End();
    

目的是将所需的标头发送回客户端以允许 CORS 正常运行 - 但是在执行此代码后,SiteClient 上的网页立即报告由于缺少“访问控制”而导致请求已被阻止- Allow-Origin' 标头丢失,我可以看到我指定的标头都没有返回给客户端。

为了让 CORS 工作,我在 SiteAPI 项目中安装了以下 nuget 包。

Microsoft.AspNet.Cors Microsoft.AspNet.WebApi.Cors

我调整了 WebApiConfig.Register() 方法以包括:

   // Web API configuration and services
   config.EnableCors();

我已经尝试了许多将过滤器属性添加到我的控制器的变体,如下所示:

[EnableCors("*", "*", "*", SupportsCredentials = true)]

我尝试从 *** 上的其他 CORS 相关问题中找到的解决方案添加我自己的自定义 ActionFilterAttribute - 例如(以及其他各种问题):

    public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
    
        filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
        base.OnActionExecuting(filterContext);

我的 web.config 文件有以下内容:

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

我的项目中包含所有这些解决方案,尽管如此,我仍然在客户端遇到 CORS 错误。

所以这里需要注意的是,我还有一个自定义过滤器,用于查找每个 API 调用的安全性 - 它适用于从 SiteApi 上运行的页面进行的所有调用。在来自 SiteClient 的调用(CORS 调用)的情况下,安全过滤器根本不会触发,尽管我在客户端上报告了 401 错误以及由于缺少 CORS 相关标头而导致的错误。

我已经清除了所有浏览器和服务器本身的缓存。这是我第一次使用 CORS,我已经厌倦了使用真正应该是一个简单的解决方案。在这里寻找解决方案,并感谢知情人士的帮助。

请求标头:

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 2
Content-Type: application/json; charset=UTF-8
Host: localhost:59569
Origin: http://localhost:61527
Referer: http://localhost:61527/Home/Index
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/80.0.3987.106 Safari/537.36 Edg/80.0.361.54

响应标头:

Cache-Control: private
Content-Length: 6115
Content-Type: text/html; charset=utf-8
Date: Wed, 19 Feb 2020 00:46:06 GMT
Server: Microsoft-IIS/10.0
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcbngyMDA4MjZcRGV2XFRlY2hJVFxFQVNJV2ViQXBwXGFwaVxWMlxHZXRDb21tYW5kcw==?=

【问题讨论】:

浏览器在 devtools 控制台中记录的确切错误是什么? 我在预检 OPTIONS 调用中得到 200,在结果调用数据时得到 401 未授权。我可以逐步执行预检调用,但即使在为 API 提供服务的代码上设置了断点我看不到没有调试 api 调用 - 我只是收到 401 错误。 【参考方案1】:

这是我使用的流程。有时浏览器不喜欢“*”。其他时候,浏览器也不喜欢 localhost。这是我使用的逻辑(根据需要修改允许标题)。这可能是因为您也不允许在允许的标头中使用访问控制标头:

[将此添加到 Global.asax]

protected void Application_BeginRequest(object sender, EventArgs e)

        var originKey =
            Request.Headers.AllKeys.FirstOrDefault(
                a => a.Equals("origin", StringComparison.InvariantCultureIgnoreCase));

        if (originKey != null && Request.HttpMethod == "OPTIONS"))
        
// Optional Whitelist check here can return without the headers below to reject CORS
            Response.Headers.Add("Access-Control-Allow-Origin", Request.Headers[originKey]);
            Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUSH, DELETE, OPTIONS");
            Response.Headers.Add("Access-Control-Allow-Headers",
                "Authorization, Content-Type, Access-Control-Allow-Headers, X-Requested-With, Access-Control-Allow-Method, Accept");

            Response.Flush();
            Response.End();
            return;
        

【讨论】:

我现在使用这段代码让我克服了 CORS 拒绝的困境。问题是它允许每个来源。在预检 ORIGIN 调用之后,我仍然收到 401,但调试器从未捕获到对数据的实际调用。 @Andrew 这一切都可以通过,但您可以轻松添加白名单检查(我省略了这一点,因为返回“*”与返回发送的 Origin 是一回事)。如果 orignKey 不是有效的 Url,此时也可以直接返回 401。至于 401,您没有在此处发送任何 Authorization 标头,因此如果您的端点上有 [Authorized] 属性,它将永远不会通过。 我在实现 IAuthenticationFilter 和 IAuthorizationFilter 的控制器上有一个 ActionFilterAttribute,我认为它应该为我处理这个问题。我继承了这个项目,并且这个过滤器适用于授权非 CORS 相关的帖子,它永远不会为 CORS 相关的帖子触发。我看不出我可以在哪里添加您在处理 OPTIONS 请求的代码中提到的标头。 嘿安德鲁。这在 global.asax 中。您将此代码添加到受保护的 void Application_BeginRequest(object sender, EventArgs e) Daniel,我在 global.asax 中有你的代码,可以在调试器中看到它执行。我看到响应标头包括具有正确原始值的 Access-Control-Allow-Origin。飞行前的 OPTIONS 调用成功,后续调用失败,仍然被阻塞。无论我在哪里设置断点,我都无法拦截第二个请求 - 在 Visual Studio 中永远不会看到它。在浏览器端,OPTIONS 收到 200 响应,但 POST 收到 401 消息,表明呼叫因 CORS 策略而被阻止。请求的资源上没有 Access-Control-Allow-Origin 标头。

以上是关于Asp.Net MVC WebApi CORS 请求失败 - 没有建议的解决方案影响结果的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WEB API 的 ASP.NET MVC 控制器级别中启用 CORS? [复制]

为 ASP .NET MVC 中的静态资源启用 CORS?

CORS 不工作 ASP.Net MVC5

在 Web API 中启用了 Asp.Net MVC CORS,但不再发送标头

ASP .NET MVC5 中的 CORS

asp.net Core MVC 2 - 配置 CORS 以接受 NULL 来源