Simplejwt & allauth - auth cookie не отправляются из браузера в бэкенд django
У меня есть бэкэнд Django, который использует allauth
и simplejwt
(оба предоставляются dj-rest-auth
) для аутентификации. Когда я делаю API-запросы с помощью API-клиента (Bruno), мои cookie-файлы аутентификации, содержащие JWT-токены, передаются, и сервер отвечает. Но я не могу добиться того же самого в JS из браузера.
Куки аутентификации получены, но не передаются в последующих запросах:
минимальный фронт-энд JS:
(async () => {
console.log("logging in...")
const loginResponse = await fetch('http://127.0.0.1:8000/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'test',
password: 'securepassword123'
})
})
const loginData = await loginResponse.json();
// response contains `set-cookie` headers
// vv prints JSON containing "access", "refresh", "username", etc.
console.log(loginData)
if (!loginResponse.ok) {
console.log('login failed :(')
return
}
console.log("getting user info...")
const userResponse = await fetch('http://127.0.0.1:8000/api/user', {
credentials: 'include'
});
const userData = await userResponse.json();
// vv prints `{detail: 'Authentication credentials were not provided.'}`
console.log(userData)
if (!userResponse.ok) {
console.log("user data fetch failed :(")
}
})();
Я уже настроил CORS, allow-credentials и т.д. в Django:
# dj-rest-auth settings ---------------------------------
# src: https://medium.com/@michal.drozdze/django-rest-apis-with-jwt-authentication-using-dj-rest-auth-781a536dfb49
SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
)
}
# djangorestframework-simplejwt
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
}
# dj-rest-auth
REST_AUTH = {
"USE_JWT": True,
"JWT_AUTH_COOKIE": "_auth", # Name of access token cookie
"JWT_AUTH_REFRESH_COOKIE": "_refresh", # Name of refresh token cookie
"JWT_AUTH_HTTPONLY": False, # Makes sure refresh token is sent
}
# cors ---------------------------------
# src: https://pypi.org/project/django-cors-headers/
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_HEADERS = (
*default_headers,
)
CORS_ALLOW_CREDENTIALS = True
SESSION_COOKIE_SAMESITE = 'None'
минимальный воспроизводимый пример:
- установите django
- следуйте этому руководству по настройке
dj-rest-auth
- создайте пользователя
- запустите прикрепленный скрипт в вашем фронт-энде (например, тег script в html)
Оказалось, что моя основная проблема заключалась в том, что файлы cookie, отправленные конечным пунктом входа в систему, не сохранялись в браузере. Мне следовало сначала проверить это, чтобы прояснить вопрос. Чтобы исправить это, мне пришлось изменить запрос /api/login
, который я делал на фронт-энде, чтобы он также содержал credentials: 'include'
. Это связано с тем, что по умолчанию при работе с кросс-оригинальными api вызовами полученные cookies не сохраняются. См. этот ответ.
Мой фиксированный простой внешний скрипт выглядит так:
(async () => {
console.log("logging in...")
const loginResponse = await fetch('http://127.0.0.1:8000/api/login', {
credentials: 'include', // <------------------------ NEW
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'test',
password: 'securepassword123'
})
})
const loginData = await loginResponse.json();
console.log(loginData)
if (!loginResponse.ok) {
console.log('login failed :(')
return
}
console.log("getting user info...")
const userResponse = await fetch('http://127.0.0.1:8000/api/user', {
credentials: 'include'
});
const userData = await userResponse.json();
console.log(userData)
if (!userResponse.ok) {
console.log("user data fetch failed :(")
}
})();