#django
Вопрос:
Когда я запрошу сброс пароля с помощью встроенного механизма django, он сгенерирует URL-адрес в электронном письме следующим образом:
https://example/accounts/reset/MTA/atspc3-7c45df8a600243fde3dfb60c44873f15/
В gmail, если я покажу URL-адрес, текст будет неопределенным, так как он создается как обычное/текстовое электронное письмо. Если я нажму ссылку в gmail или Outlook, то она отправится (возможно, после перенаправления, я не могу сказать, так как это происходит так быстро):
https://example.com/accounts/reset/MTA/set-password/
И там написано
Password reset unsuccessful
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
Однако если я скопирую и вставлю URL-адрес в браузер, он будет работать. Однако никто не копирует и не вставляет URL-адрес, все они нажимают на ссылку и говорят, что она не работает.
Я не понимаю, почему нажатие на ссылку не работает, так как она правильная?
Мне удалось добавить ведение журнала в код Django, я добавил ведение журнала в:
contrib.auth.views -> PasswordResetConfirmView.dispatch (line 247)
Как вы можете видеть из следующих двух журналов, в обоих сценариях они вызываются с точно такими же локальными объектами (я печатаю локальные объекты()), однако это представление, похоже, устанавливает токен в сеансе, а затем перенаправляет. однако после перенаправления, если кто-то щелкнул ссылку в электронном письме, файл cookie сеанса исчез, и, следовательно, он не работает. Я все еще не понимаю, почему
СКОПИРУЙТЕ и вставьте URL-адрес (рабочий)
------------------------------------------------------------
# First call to dispatch:
token: atspc3-7c45df8a600243fde3dfb60c44873f15
Entered dispatch {'self': <django.contrib.auth.views.PasswordResetConfirmView object at 0x7f20e63c2220>, 'args': (<WSGIRequest: GET '/accounts/reset/MTA/atspc3-7c45df8a600243fde3dfb60c44873f15/'>,), 'kwargs': {'uidb64': 'MTA', 'token': 'atspc3-7c45df8a600243fde3dfb60c44873f15'}, 'token': 'atspc3-7c45df8a600243fde3dfb60c44873f15', '__class__': <class 'django.contrib.auth.views.PasswordResetConfirmView'>}
user is not None
token is NOT reset
token atspc3-7c45df8a600243fde3dfb60c44873f15
Verfiy sessions token atszyc-e7c578496e3438f9dee367fcbebfabb1
redirect url /accounts/reset/MTA/set-password/
Djnago logging start
------------------------------------------------------------
# Second call to dispatch (after redirect):
token: set-password
Entered dispatch {'self': <django.contrib.auth.views.PasswordResetConfirmView object at 0x7f20e63c2220>, 'args': (<WSGIRequest: GET '/accounts/reset/MTA/set-password/'>,), 'kwargs': {'uidb64': 'MTA', 'token': 'set-password'}, 'token': 'set-password', '__class__': <class 'django.contrib.auth.views.PasswordResetConfirmView'>}
user is not None
token is self reset, session token: atspc3-7c45df8a600243fde3dfb60c44873f15
НАЖМИТЕ ссылку в электронном письме (не работает)
------------------------------------------------------------
# First call to dispatch:
token: atspc3-7c45df8a600243fde3dfb60c44873f15
Entered dispatch {'self': <django.contrib.auth.views.PasswordResetConfirmView object at 0x7f20d9a77190>, 'args': (<WSGIRequest: GET '/accounts/reset/MTA/atspc3-7c45df8a600243fde3dfb60c44873f15/'>,), 'kwargs': {'uidb64': 'MTA', 'token': 'atspc3-7c45df8a600243fde3dfb60c44873f15'}, 'token': 'atspc3-7c45df8a600243fde3dfb60c44873f15', '__class__': <class 'django.contrib.auth.views.PasswordResetConfirmView'>}
user is not None
token is NOT reset
token atspc3-7c45df8a600243fde3dfb60c44873f15
Verfiy sessions token atszyc-e7c578496e3438f9dee367fcbebfabb1
redirect url /accounts/reset/MTA/set-password/
------------------------------------------------------------
# Second call to dispatch (after redirect):
token: set-password
Entered dispatch {'self': <django.contrib.auth.views.PasswordResetConfirmView object at 0x7f20d9adde20>, 'args': (<WSGIRequest: GET '/accounts/reset/MTA/set-password/'>,), 'kwargs': {'uidb64': 'MTA', 'token': 'set-password'}, 'token': 'set-password', '__class__': <class 'django.contrib.auth.views.PasswordResetConfirmView'>}
user is not None
token is self reset, session token: None
Вот инструкции журнала, которые я добавил в contrib.auth.views -> PasswordResetConfirmView.dispatch (line 247)
:
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
log_info('------------------------------------------------------------')
token = kwargs['token']
log_info('token:', token)
log_info('Entered dispatch', str(locals()))
assert 'uidb64' in kwargs and 'token' in kwargs
self.validlink = False
self.user = self.get_user(kwargs['uidb64'])
if self.user is not None:
token = kwargs['token']
log_info('user is not None')
if token == self.reset_url_token:
session_token = self.request.session.get(INTERNAL_RESET_SESSION_TOKEN)
log_info('token is self reset, session token:', session_token)
if self.token_generator.check_token(self.user, session_token):
# If the token is valid, display the password reset form.
self.validlink = True
return super().dispatch(*args, **kwargs)
else:
log_info('token is NOT reset')
if self.token_generator.check_token(self.user, token):
# Store the token in the session and redirect to the
# password reset form at a URL without the token. That
# avoids the possibility of leaking the token in the
# HTTP Referer header.
self.request.session[INTERNAL_RESET_SESSION_TOKEN] = token
log_info('token', token)
log_info('Verfiy sessions token', self.request.session[INTERNAL_RESET_SESSION_TOKEN])
redirect_url = self.request.path.replace(token, self.reset_url_token)
log_info('redirect url', redirect_url)
return HttpResponseRedirect(redirect_url)
else:
log_info('failed token generator check')
Обратите внимание, что в обоих случаях запрос имеет следующие атрибуты (я подумал, что это может быть проблема с защищенными файлами cookie).:
request.scheme: https
request.is_secure: True
request.full path /accounts/reset/MTA/set-password/
or
request.full path /accounts/reset/MTA/atspc3-7c45df8a600243fde3dfb60c44873f15/
Комментарии:
1. Не могли бы вы поделиться своим шаблоном электронной почты, urls.py а виды?
2. @black, я использую встроенный шаблон электронной почты, URL-адреса и представления. Я ничего не настраивал. Это сбивает с толку, я не знаю, что не работает. ссылка работает, ссылка в электронном письме та же, нажатие на ссылку в электронном письме не работает. Я бы исправил URL-адрес, но URL-адрес уже правильный.
3. Ситуация определенно неожиданная, поэтому нам нужно просмотреть ваш код, чтобы понять, в чем проблема.
4. @black, спасибо за продолжение, к сожалению, это не мой код, но, пожалуйста, посмотрите некоторые записи, которые я добавил в код django.
Ответ №1:
В редких случаях, когда у кого-то еще есть эта проблема, у меня была в файле настроек:
SESSION_COOKIE_SAMESITE = 'Strict'
Изменение его на разрешенный файл cookie для сохранения из внешнего домена (почтовый клиент):
SESSION_COOKIE_SAMESITE = 'Lax' # default value
Обратитесь к https://docs.djangoproject.com/en/stable/ref/settings/#session-cookie-samesite