CORS: невозможно использовать подстановочный знак в Access-Control-Allow-Origin, когда флаг учетных данных имеет значение true

296

У меня есть установка, включающая

Фронтенд-сервер (Node.js, домен: localhost: 3000) <---> Бэкэнд (Django, Ajax, домен: localhost: 8000)

Браузер <- webapp <- Node.js (обслуживать приложение)

Браузер (webapp) -> Ajax -> Django (обслуживать POST-запросы ajax)

Теперь моя проблема заключается в настройке CORS, которую веб-приложение использует для выполнения вызовов Ajax на внутренний сервер. В хроме я продолжаю получать

Невозможно использовать подстановочный знак в Access-Control-Allow-Origin, если флаг учетных данных имеет значение true.

не работает на Firefox либо.

Моя настройка Node.js:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://localhost:8000/');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
};

И в Django я использую это промежуточное программное обеспечение вместе с этим

Веб-приложение делает запросы как таковые:

$.ajax({
    type: "POST",
    url: 'http://localhost:8000/blah',
    data: {},
    xhrFields: {
        withCredentials: true
    },
    crossDomain: true,
    dataType: 'json',
    success: successHandler
});

Итак, заголовки запросов, которые отправляет веб-приложение, выглядят так:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: 'GET,PUT,POST,DELETE'
Content-Type: application/json 
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: csrftoken=***; sessionid="***"

И вот заголовок ответа:

Access-Control-Allow-Headers: Content-Type,*
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Type: application/json

Куда я иду не так ?!

Редактировать 1: я использовал chrome --disable-web-security, но теперь хочу, чтобы все действительно работало.

Изменить 2: Ответ:

Итак, решение для меня django-cors-headersконфиг:

CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000' # Here was the problem indeed and it has to be http://localhost:3000, not http://localhost:3000/
)
ixaxaar
источник
1
Для меня это localhost: 3000 без http, например: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Андрей
Вы имеете в виду, что вы разрабатываете фронтенд и бэкэнд на одном ПК?
fanhualuojin154873
как насчет фронтэнда и бэкенда в разных ПК?
fanhualuojin154873
@ixaxaar, почему вы говорите с http работает для вас? у нас все только `'localhost: 3000'` работает.
244 мальчика
@ 244boy да, дело не в этом http, а /в конце. Я полагаю, что пропуск http может сработать, но я действительно не работал над этим несколько лет, так что не знаю, что работает сейчас!
ixaxaar

Ответы:

247

Это часть безопасности, вы не можете этого сделать. Если вы хотите разрешить учетные данные, то вы Access-Control-Allow-Originне должны использовать *. Вам нужно будет указать точный протокол + домен + порт. Для справки смотрите эти вопросы:

  1. Подстановочные поддомены Access-Control-Allow-Origin, порты и протоколы
  2. Совместное использование ресурсов с использованием учетных данных

Кроме того, *это слишком разрешительно и будет побеждать использование учетных данных. Так что установите http://localhost:3000или http://localhost:8000как разрешить заголовок источника.

user568109
источник
45
Но что, если существует более одного домена?
aroth
13
@aroth Вы можете дать список доменов. Связанные вопрос: stackoverflow.com/questions/1653308/...
user568109
13
@ user568109 Не могли бы вы объяснить, «Кроме того, *это слишком разрешительно и будет препятствовать использованию учетных данных.»?
Хьюго Вуд
12
Что такое «точный домен», если запрос приходит с мобильного устройства, как это может случиться с Cordova?
Кристиан
8
@ Кристиан вроде старый, но если кому-то все же интересно, эта проблема возникает только для приложений, работающих в браузерах, потому что эта ошибка выдается браузером по соображениям безопасности. Другие клиенты, такие как мобильное приложение, почтальон или любой другой внутренний код, использующий http-клиент для отправки запроса, не будут иметь этой проблемы, поэтому вам не нужно беспокоиться о происхождении и точном домене .
Alisson
32

Если вы используете промежуточное программное обеспечение CORS и хотите отправить withCredentialлогическое значение true, вы можете настроить CORS следующим образом:

var cors = require('cors');    
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
Хамид
источник
16

Если вы используете, expressвы можете использовать пакет cors , чтобы разрешить использование CORS, вместо написания промежуточного программного обеспечения;

var express = require('express')
, cors = require('cors')
, app = express();

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
источник
12
Ах, теперь это более удобно, однако, результат тот же :( Кстати, я используюapp.use(cors({credentials: true}));
ixaxaar
1
Возможно, вы захотите взглянуть на это промежуточное ПО Django CORS, которое тестируется.
Bulkan
1
Итак, у вас есть два промежуточных программного обеспечения Django? Я бы использовал только django-cors-headerприложение. Убедитесь , что вы добавить локальный для CORS_ORIGIN_WHITELISTнастройки и набор CORS_ALLOW_CREDENTIALSдляTrue
Bulkan
1
Да человек, пытался что прежде чем без толка, было CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )и CORS_ALLOW_CREDENTIALS = True я получаю эти заголовки:Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://localhost:3000/ Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Content-Type: application/json
ixaxaar
5
После прочтения этой документации: github.com/expressjs/corsuse i, используя эту конфигурацию: app.use (cors ({credentials: true, origin: ' localhost: 3001 '})); работает на меня.
аллель
11

попытайся:

const cors = require('cors')

const corsOptions = {
    origin: 'http://localhost:4200',
    credentials: true,

}
app.use(cors(corsOptions));
Железный щит
источник
6

Если вы хотите разрешить все источники и сохранить учетные данные, это сработало для меня:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Squirrl
источник
@TSlegaitis Ха-ха, вот почему это работает для всех источников, но сохраняет учетные данные. Я не рекомендовал бы это для безопасности, но это работает.
Белка
2

(Изменить) Ранее рекомендованное дополнение больше не доступно, вы можете попробовать это другое


Для целей разработки в Chrome установка этого дополнения избавит от этой конкретной ошибки:

Access to XMLHttpRequest at 'http://192.168.1.42:8080/sockjs-node/info?t=1546163388687' 
from origin 'http://localhost:8080' has been blocked by CORS policy: The value of the 
'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' 
when the request's credentials mode is 'include'. The credentials mode of requests 
initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

После установки убедитесь, что вы добавили свой шаблон URL в папку Intercepted URLs, щелкнув значок AddOn ( CORS , зеленый или красный) и заполнив соответствующее текстовое поле. Пример шаблона URL для добавления сюда, с которым http://localhost:8080будет работать:*://*

Эриэль Маримон
источник
Я получил это только после установки, какие-нибудь идеи?
Джалил
Это сработало для меня. Предупреждение, если у вас есть другие подобные надстройки, вы должны удалить его, прежде чем попробовать это.
ФилиппоГ
пожалуйста, исправьте неработающую ссылку
Luk Aron
Похоже, что оригинальное дополнение было удалено, я добавил новую рекомендацию как (Изменить) вверху
Эриэль Маримон
1

Это работает для меня в разработке, но я не могу посоветовать, что в производстве это просто другой способ выполнения работы, который еще не был упомянут, но, вероятно, не самый лучший. Во всяком случае здесь идет:

Вы можете получить источник из запроса, а затем использовать его в заголовке ответа. Вот как это выглядит в экспрессе:

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', req.header('origin') );
  next();
});

Я не знаю, как это будет выглядеть с вашей настройкой Python, но это должно быть легко перевести.

Renaud
источник
Документы разработчика Mozilla расширяют идею изменения разрешенного источника на источник из запроса. Предлагается добавить заголовок HTTP-ответа «Vary: Origin» и разрешенные домены белого списка.
Рамзис