Сначала небольшая предыстория, которая может показаться вам интересной: это частично связано с токеном CSRF, а частично — с сеансом.
Способ работы CSRF в Django заключается в том, что один и тот же токен отражается как в шаблоне, так и в сеансе — так Django проверяет, соответствуют ли входящие данные формы сеансу пользователя и не являются ли они инъекцией кого-то злого.
Когда вы переходите от выхода из системы к входу в систему, вы обмениваете сеанс без аутентификации на сеанс с аутентификацией, что означает, что вы получаете новый сеанс — с новым токеном CSRF в сеансе. Этот сеанс используется на всех ваших вкладках, даже на тех, которые уже открыты, и даже в браузере, таком как Chrome, в котором есть отдельные процессы для каждой вкладки.
Таким образом, вход на вкладке A дает вкладке B файл cookie сеанса, который больше не соответствует токену CSRF, встроенному в страницу, поэтому вкладка B генерирует исключение CSRF. Если вы обновили вкладку B после входа на вкладку A (и предполагая, что вошедший в систему пользователь все еще может видеть экран входа), он должен позволить вам снова войти в систему, потому что токен CSRF обновленной страницы снова будет соответствовать сессия.
С точки зрения изящной обработки этого, я предлагаю вам добавить пользовательский вид обработчика 403, который либо показывает более красивая страница 403 вашего собственного дизайна или, если вы считаете это приемлемым, перенаправляет пользователя куда-то еще (но я бы проверил, что это перенаправление происходит только в том случае, если оно происходит в ответ на поддельный вход в систему, как описано в вашем вопросе)
Еще одна вещь, которую нужно сказать: вариант использования, о котором вы говорите (две открытые вкладки), довольно тонкий - я бы просто использовал пользовательскую страницу 403, чтобы сделать ее красивее, а не перенаправлять.
Если вам интересно, посмотрите источник а>:
if SESSION_KEY in request.session:
if request.session[SESSION_KEY] != user.pk:
# To avoid reusing another user's session, create a new, empty
# session if the existing session corresponds to a different
# authenticated user.
request.session.flush()
else:
request.session.cycle_key()
Когда вы начинаете с неаутентифицированного пользователя, user.pk никак не может быть таким же, как PK вашего аутентифицированного пользователя, поэтому вы получаете новый сеанс.
(Если вы снова войдете в систему как тот же пользователь, вы получите вызов cycle_key(), который может фактически сохранить токен CSRF - я не проверял)
person
Steve Jalim
schedule
08.04.2014