HTTP-ответ Django всегда устанавливает куки `sessionid`, и данные сессии не сохраняются

Я создал пользовательский бэкенд и связанное с ним промежуточное ПО, которое регистрирует пользователей при единственном условии, что вместе с запросом передается cookie ID_TOKEN (аутентификация осуществляется с помощью AWS Cognito + Lambda Edge, управляемой AWS CouldFront).

Мой код в значительной степени основан на django.contrib.auth.backends.RemoteUserBackend и связанном с ним промежуточном программном обеспечении middleware django.contrib.auth.middleware.RemoteUserMiddleware.

В то время как работа с пользовательскими данными сессии работает нормально как локально, так и в контейнере Docker с помощью runserver + юнит-тесты проходят, в продакшене (код, запущенный в контейнере на AWS ECS) я теряю все данные сессии от одного запроса/ответа к другому. Из того, что я могу видеть в сетевой вкладке Firefox, заголовок set-cookie всегда отправляется с HTTP-ответом, что приводит к потере данных сессии. Я предполагаю, что они должны быть смыты также на стороне бэкэнда (сессии используют хранилище базы данных, производство работает на gunicorn).

Я установил SESSION_COOKIE_SECURE = True в продакшене, но это не решило проблему. Более того, использование django_extensions и его runserver_plus с автоматически сгенерированным сертификатом для локального использования HTTPS также не позволило мне воспроизвести проблему.

Вот один set-cookie пример: set-cookie sessionid=rlc...tn; expires=Mon, 03 Feb 2025 14:29:53 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax; Secure

Кто-нибудь уже сталкивался с подобной проблемой?

Сессия смывается из-за следующих строк в вашем промежуточном ПО:

if request.user.is_authenticated:
    if request.user.get_username() == token.username and not has_id_token_digest_changed:
        return  # username and token did not change, do nothing

    self._remove_invalid_user(request)

Вызов self._remove_invalid_user(request) является проблемой, так как при этом происходит выход пользователя из системы, что приводит к стиранию сессии в целях безопасности. Поскольку вы упомянули, что разработали это после обращения к RemoteUserMiddleware, соответствующие строки там выглядят следующим образом:

if request.user.is_authenticated:
    if request.user.get_username() == self.clean_username(username, request):
        return self.get_response(request)
    else:
        # An authenticated user is associated with the request, but
        # it does not match the authorized user in the header.
        self._remove_invalid_user(request)

Обратите внимание, что в этом случае _remove_invalid_user вызывается только в том случае, если имя пользователя удаленного пользователя не совпало с именем пользователя вошедшего в систему. В вашем случае вы вызываете метод, даже если имя пользователя совпало, но ID-токен не совпал.

Вы, похоже, пытаетесь проверить, изменился ли ID-токен или нет, проверяя его хэш, но это не имеет особого смысла, учитывая, что ID-токен - это JWT, который обычно не имеет длительного срока действия. Вполне возможно, что измененный токен предназначен для той же личности пользователя и является просто заменой токена с истекшим сроком действия. Если вы хотите подтвердить, что токен принадлежит тому же пользователю, вам следует использовать какое-либо идентифицирующее утверждение из токена, например утверждение sub и т. д. Пока предположим, что ваше имя пользователя идентифицирует его однозначно, вы можете изменить эти строки следующим образом:

if request.user.is_authenticated:
    if request.user.get_username() == token.username:
        return  # username did not change, do nothing
    else:
        self._remove_invalid_user(request)

Благодаря вам, Абдул Азиз Баркат, я смог свести проблему к слишком строгому белому списку файлов cookie в AWS CloudFront. Спасибо!

Добавление обоих стандартных имен куки Django sessionid и csrftoken в белый список куки решило мою проблему (сессия сохраняется вместе с данными сессии и проверка CSRF проходит успешно).

Для тех из вас, кто интересуется некоторыми вопросами, связанными с облаком / IaC, помните, что вам нужно правильно настроить политику Cookies в CloudFront. Вот немного документации Terraform об этом.

Вернуться на верх