Подтвердить что ты не робот

XmlHttp.getResponseHeader + Не работает для CORS

У меня есть asp.NET WCF на .NET 4. Этот сервис используется для аутентификации пользователей. Мы отправляем имя пользователя и пароль, а затем должен быть возвращен заголовок HTTP с включенным файлом cookie аутентификации. Используя локальную тестовую страницу, это работает правильно. Я сейчас пытаюсь получить доступ к информации заголовка между доменами. Я установил свою тестовую страницу на другой компьютер и настроил вызов через WCF. Вызов работает, и ответ "данные" в вызове правильный. Однако я не могу получить доступ к информации заголовка с помощью одного из следующих:

alert(xmlHttp.getAllResponseHeaders());

или же

alert(xmlHttp.getResponseHeader("Set-Cookie"));

Используя отладчик в IE и плагин "Live HTTP Header" для Firefox, я вижу, что возвращается информация заголовка.

На моей глобальной странице AJAX я устанавливаю ответ для обработки CORS.

private void EnableCrossDomainAjaxCall()
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");


    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {

        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");

        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }

}

Это AJAX, который я использую для вызова службы:

$("#btnLogin").click(function(e) {
    var geturl;
    geturl = $.ajax({
        // type: "POST",
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: 'http://10.0.4.66/AuthenticationService.svc/Login?Name=test&password=pwsd',
        // url: '../SecurityServer/AuthenticationService.svc/Login?Name=test&password=pwsd',
        dataType: "jsonp",
        error: function(request, status, error) {
            alert('Error Occured');
        },
        crossdomain: true,
        success: function(data, textStatus, xmlHttp) {
            // alert(xmlHttp.getResponseHeader("Content-Type"));
            document.write(xmlHttp.getResponseHeader("Content-Type") + "<br/>");
            alert(xmlHttp.getAllResponseHeaders());
            alert(xmlHttp.getResponseHeader("Set-Cookie"));
            var headers = '';
            var headerPair = xmlHttp.getAllResponseHeaders('wcfCookie').split("\r\n");
            var output = '';
            $.each(headerPair, function(key, line) {
                var parts = line.split(':');

                if (parts[0] == 'wcfCookie') {
                  ChocChip = parts[1]
                  return false
                }

            });
        }
    });

Ниже приведена информация о моем заголовке, извлеченная из "заголовков HTTP в реальном времени".

Date: Mon, 04 Feb 2013 12:12:40 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Access-Control-Allow-Origin: *
Set-Cookie: wcfCookie=8D38D5D6A0F138FEB595DD016F7694EDDF3E6757C82ED3D419F5047A5294974C1885487465CEC0A0BCC2B3802C7B03FF9F5370A05D4CCBDDDABCB1558C3816044BF4F78209BF38C6B1A7CAD34CD3C85C40B8515CFB1C2B2694BC78803D8DACB4
Content-Length: 65
Cache-Control: application/json; charset=utf-8
Content-Type: application/x-javascript
4b9b3361

Ответ 1

Сначала немного фона:

Вы используете Access-Control-Allow-Headers, который указывает, какие заголовки запросов клиенту разрешено отправлять, но вы не указываете, какие заголовки ответов клиенту разрешено читать. Чтобы клиент мог читать непростые заголовки ответов, вам нужно использовать Access-Control-Expose-Headers. На странице HTML5 Rocks CORS:

Во время запроса CORS метод getResponseHeader() может получить доступ только к простым заголовкам ответа. Простые заголовки ответов определяются следующим образом:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Истекает
  • Last-Modified
  • Pragma

Если вы хотите, чтобы клиенты имели доступ к другим заголовкам, вы должны использовать заголовок Access-Control-Expose-Headers. Значение этого заголовка представляет собой список заголовков ответов с разделителями-запятыми, которые вы хотите предоставить клиенту.

Итак, учитывая эту новую информацию, вы можете:

HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "Set-Cookie");

... но там больше, чем это.

Теперь, фактический ответ:

Здесь еще одна серьезная проблема: спецификация XHR явно запрещает чтение Set-Cookie. Это потому, что это функционально кросс-доменная атака, прибивающая cookie.

Предположим, что домен A выполняет междоменный запрос в домен B. Когда домен B устанавливает файлы cookie, он устанавливает cookie только для домена для домена B. Любая попытка домена A для чтения файлов cookie домена B является нарушением политики одинакового происхождения для доступа к файлам cookie.

Я не знаю WCF, поэтому я не уверен, что лучше всего делать то, что вы хотите, но я предполагаю, что решение может состоять в том, чтобы передать токен аутентификации не через файлы cookie (например, a X-WCF-Auth header?), который домен A читает, а затем устанавливает свой собственный файл cookie.

Ответ 2

Политики безопасности браузера могут блокировать ваш ответ, потому что вы не установили:

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials","true");

Если это не помогает, попробуйте добавить

xhrFields: { withCredentials: true }

к вашим параметрам ajax также может быть полезно.