Почему Chrome не может устанавливать файлы cookie
Я получил ответ от моего сервера. Заголовки ответа содержат действительный Set-Cookie. Chrome Response/Cookies говорит, что у меня есть 1 файл cookie, хорошо. Но... Файл cookie не устанавливается в DevTools/Application/Cookies
/*
My frontend on Vue
I renamed 127.0.0.1 to www.example.com
So running on www.example.com:80 or just www.example.com
*/
let response = await axios({
method: 'post',
url: 'http://127.0.0.1:3000/api/login', // my Node server on 3000 port
data: {
email : login,
password: password,
},
})
/*
My backend part on Node.js+Express
Running on localhost:3000 or 127.0.0.1:3000
CookieParser() is setted
*/
let options = {
maxAge: 345600000,
httpOnly: true,
path: '/',
}
res
.cookie('test', 'test', options)
.cookie('access_token', token, options) //token contains a JWT string
.send('');
/*
Chrome Response Headers
*/
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 09 Feb 2020 08:52:22 GMT
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Set-Cookie: test=test; Max-Age=345600; Path=/; Expires=Thu, 13 Feb 2020 08:52:22 GMT; HttpOnly
Set-Cookie: access_token=example; Max-Age=345600; Path=/; Expires=Thu, 13 Feb 2020 08:52:22 GMT; HttpOnly
X-Powered-By: Express
/*
Chrome request headers
*/
Accept: application/json, text/plain, '*/*'
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 45
Content-Type: application/json;charset=UTF-8
Host: 127.0.0.1:3000
Origin: http://www.example.com
Pragma: no-cache
Referer: http://www.example.com/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
Более того, я пытался использовать Microsoft Edge, но проблема не исчезла. Почему браузеры не могут устанавливать файлы cookie, если они знают о получении файлов cookie?
4 ответа
Если вы хотите немного почитать в общих чертах, я предлагаю вам поискать руководства по CORS (совместное использование ресурсов из разных источников) и, в частности, как устанавливать файлы cookie при использовании CORS.
Используя исходный код, вам нужно будет изменить его, чтобы установить withCredentials
к true
:
let response = await axios({
method: 'post',
url: 'http://127.0.0.1:3000/api/login', // my Node server on 3000 port
data: {
email : login,
password: password,
},
withCredentials: true
})
За кулисами это установит withCredentials
флаг на XMLHttpRequest
:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
После этого в консоли появятся ошибки CORS. Если вы исправите эти ошибки, вы сможете заставить его работать. Эти ошибки будут включать...
Во-первых, серверу нужно будет вернуть заголовок Access-Control-Allow-Credentials: true
. Это также относится к предварительному запросу OPTIONS.
Во-вторых, вы сейчас используете Access-Control-Allow-Origin: *
но это не разрешено для запросов с использованием учетных данных. Это должно бытьAccess-Control-Allow-Origin: http://www.example.com
. То же самое и для предполетной подготовки.
На этом этапе файл cookie должен быть установлен в большинстве браузеров (подробнее об особенностях браузера позже).
Чтобы файлы cookie добавлялись в последующие запросы, вам также необходимо установить withCredentials: true
по этим запросам. Остальные изменения заголовка, описанные выше, также должны быть применены. Файлы cookie не будут включены в предварительный запрос, а будут включены только в основной запрос.
Увидеть файлы cookie в инструментах разработчика браузера не совсем просто. Как правило, инструменты показывают только файлы cookie, установленные для того же источника, что и текущая страница, но не включают файлы cookie, установленные с помощью запросов CORS. Чтобы увидеть эти файлы cookie, вам нужно открыть другую вкладку браузера и указать URL-адрес, который начинается с того же источника, что и запрос CORS. Однако будьте осторожны, вам нужно выбрать URL-адрес, который не будет устанавливать файлы cookie, иначе это ничего не доказывает.
Другой способ проверить, какие файлы cookie установлены, - отправить другой запрос (с withCredentials
) и посмотрите, какие файлы cookie будут отправлены.
Затем у нас есть проблемы, связанные с браузером...
В Safari очень сложно настроить файлы cookie для CORS. Если Safari является для вас целевым браузером, я предлагаю провести дополнительное исследование.
Во-вторых, Chrome 80 должен значительно изменить правила использования файлов cookie CORS. Видеть:
https://www.chromium.org/updates/same-site
Вы уже будете видеть предупреждения об этом на своей консоли в более старых версиях Chrome. Короче говоря, файлы cookie CORS необходимо будет обслуживатьhttps
и установите директивы Secure
а также SameSite=None
.
Если вы используете Axios или Fetch - они по умолчанию не отправляют куки. Если вы пойдете и зайдете в инструменты dav - (вкладка приложения -> куки), вы должны их увидеть. это не проблема с хромами, а с тем, как вы пытаетесь отправить их обратно, в выборке вам нужно добавитьcredentials: 'include',
объекту option, в аксиомах это {withCredentials: true}
Столкнулся с той же проблемой, что и у OP, оказалось, что моя довольно проста:
Нужно обратить внимание при использованииaxios
, если вы используете этот синтаксис:axios.post()
Что я сделал не так:
axios.post(
"url",
{ withCredentials: true } // <- this is request body
);
Исправить:
axios.post(
"url",
null,
{ withCredentials: true } // <- this is config
);
если вы используете экспресс, можно использовать экспресс-сеанс для файла cookie сеанса.
из официальной документации: https://www.npmjs.com/package/express-session
если вы используете
cross-site origin and https
безопасное соединение:
session: {
cookie: {
maxAge: 1000*60*60*1,
httpOnly: true, //set false if you want to change the cookie using JavaScipt
secure: true,
sameSite: 'none'
}
}
и не забудьте установить:
app.set('trust proxy', 1)
используя экспресс js
иначе в
localhost
ты можешь использовать
session: {
cookie: {
maxAge: 1000*60*60*1,
httpOnly: true, //set false if you want to change the cookie using JavaScipt
secure: false,
sameSite: 'lax'
}
}