django allauth CSRF Ошибка сбоя проверки

Позвольте мне объяснить, что я делаю?

В моем браузере открыты две вкладки, на которых отображается моя страница входа (простая форма имени пользователя и пароля).

Использование вкладки 1: я вхожу в систему, указав правильные учетные данные. работает правильно.

Используя вкладку 2: (без обновления) я снова пытаюсь войти в систему, используя те же или другие учетные данные, это выдает запрещенную ошибку 403. Причина сбоя: токен CSRF отсутствует или неверен.

Я знаю, я делаю что-то глупое, что я пытаюсь войти в систему, когда я уже вошел в нее.

Я хочу предотвратить возникновение грязной ошибки 403 и сделать процесс плавным, так как во втором запросе на вход следует просто игнорировать, когда кто-то уже вошел в систему или что-то еще, что не нарушает поток. как мне это сделать?

Я использую Django==1.6.2 и django-allauth==0.14.1.


person Crazyshezy    schedule 08.04.2014    source источник


Ответы (2)


Сначала небольшая предыстория, которая может показаться вам интересной: это частично связано с токеном 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

вы должны сделать что-то вроде этого:

def userlogin(request):
    if request.method=='POST':
        user = request.user
        if user.is_authentificated:
            return HttpResponceRedirect('some_url')
        else:
            #your login procedure
person user3336706    schedule 08.04.2014