预检请求没问题,然后,经过身份验证,响应不包含允许 cors 标头

Posted

技术标签:

【中文标题】预检请求没问题,然后,经过身份验证,响应不包含允许 cors 标头【英文标题】:Preflight request is ok, then, after auth, response does not contain allow cors header 【发布时间】:2017-10-12 19:47:01 【问题描述】:

在 IIS 8.5 上部署的 Asp MVC 5 应用程序。 需要启用来自多个客户端的 ajax 请求。

我在 WebApiConfig.cs 中的服务器端

config.EnableCors();

在控制器中:

[EnableCors(origins: "http://localhost:59901", headers: "*", methods: "*", SupportsCredentials = true)]
public class ItemController : Controller

客户端

$("#getItem").on("click", function (e) 
    var myurl = "http://servername/item/details/1"

    $.ajax(
        url: myurl,
        type: "GET",
        dataType: "JSON",
        xhrFields: 
            withCredentials: true
        ,
        contentType: "application/json; charset=utf-8",
        error: function (jqXHR, textStatus, errorThrown) 
            $('#result').text(jqXHR.responseText || textStatus);
        ,
        success: function (result) 
            $('#result').text(result);
        
    );
);

从 VisualStudio Origin 运行的客户端是 http://localhost:59901。

运行 ajax 请求,我在 fiddler 中得到以下信息:

1.预检请求/响应

OPTIONS http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4

HTTP/1.1 200 OK
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://localhost:59901
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:54 GMT
Content-Length: 0

2。 GET 请求没有凭据/401 错误响应

GET http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/json; charset=utf-8
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:54 GMT
Content-Length: 1352
Proxy-Support: Session-Based-Authentication

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Autorizzazione negata: accesso negato a causa di credenziali non valide.</title>
....
</head>
<body>
<div id="header"><h1>Errore del server</h1></div>
....
</body>
</html>

3.带有 NTLM 令牌的 GET 请求,用于不带允许 CORS 标头的身份验证/响应

GET http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Authorization: Negotiate <...NTLM TOKEN HERE ...>
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/json; charset=utf-8
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4


HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.5
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:58 GMT
Content-Length: 8557

"id":1, .....

问题

为什么在为 CORS 启用 MVC 应用程序并看到对预检请求的正确响应后,在 NTLM 身份验证后获得的响应不包含预期的 Access-Control-Allow-Origin 标头?

【问题讨论】:

您所做的编辑实际上是对该问题的回答,因此您可以考虑将其添加为实际答案并自己接受它,以便遇到此问题的其他人可以更轻松地看到解决方案是(甚至可以投票...) 【参考方案1】:

已解决(……暂时……) 调用的操作是返回 Json 的控制器操作。这不适用于 CORS。我需要创建一个 API 控制器,不能使用现有的控制器。这会导致代码重复,但我现在没有时间重构整个应用程序以对 MVC 和 API 使用单个控制器

【讨论】:

【参考方案2】:

我不确定它是否会对您有所帮助,但它可能会对希望同时启用 NTLMCORS 的其他人有所帮助。

CORS 启用

public static class WebApiConfig

    public static void Register(HttpConfiguration config)
    
        var corsAttr = new EnableCorsAttribute("*", "*", "*")  SupportsCredentials = true ;
        //SupportsCredentials = true means that we will add Access-Control-Allow-Credentials to the response.
        config.EnableCors(corsAttr);
    

SupportsCredentials = true 表示我们将在响应中添加Access-Control-Allow-Credentials

其他解决方案,

global.asax.cs - 正确回复允许来自另一个域的调用者接收数据的标头

protected void Application_AuthenticateRequest(object sender, EventArgs e)

    if (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 中,我只是 EnableCors(),然后我在 Controller 类 [EnableCors()] 中使用 DataAnnotation 和属性,包括 SupportCredentials=true。对预检请求的响应一切正常,返回正确的标头。然后我进行身份验证,成功后的身份验证响应没有所有需要的标头。我还尝试了您建议的第二种方法,但是我没有在 global.asax.cs 中添加标头,而是在 Web.Config 中添加了它们;在这种情况下,标头被添加了两次,没有任何需要的工作。 docs.microsoft.com/en-us/aspnet/web-api/overview/security/… @kranz 是的,你也可以这样做。更多帮助:msdn.microsoft.com/en-us/magazine/dn532203.aspx @kranz 当我添加 web.config 时,一件事 cros header 对我来说并不完美。所以如果你需要添加它 global.asax.cs。 我不能使用 Owin/Oauth,这是一个 Intranet 应用程序,NTLM 身份验证是唯一的方法。

以上是关于预检请求没问题,然后,经过身份验证,响应不包含允许 cors 标头的主要内容,如果未能解决你的问题,请参考以下文章

为啥经过身份验证的 CORS 请求的预检 OPTIONS 请求在 Chrome 中有效,但在 Firefox 中无效?

CORS 预检请求返回带有 Windows 身份验证的 HTTP 401

对预检请求的响应未通过访问控制检查:在标头中使用身份验证时,它没有 HTTP ok 状态 [关闭]

带有预检的 POST 请求包含允许的来源,但错误是不允许来源

OPTIONS 请求身份验证

CORS:对预检请求的响应未通过访问控制检查:预检请求不允许重定向