Я пытаюсь создать функцию сброса пароля в моем приложении Django / React.Я использую django-contrib-auth для серверной части, и большая часть этого работает хорошо.Однако я не могу получить правильный запрос POST для фактического обновления пароля.Вот рабочий процесс.
- Пользователь нажимает ссылку «забыл пароль» и отображается форма, в которой он вводит свой адрес электронной почты.
- Он получает электронное письмо, содержащее ссылку, по которой нужно щелкнуть.
- Они нажимают на ссылку и посещают страницу, где они дважды вводят свой новый пароль и нажимают «Отправить».
Вот в чем проблема.Если я использую встроенную форму, сгенерированную django-contrib-auth, пароль будет сброшен правильно.Но я хочу использовать форму, сгенерированную React, и на этой странице я отправляю запрос на выборку к той же конечной точке.
Вот запрос на выборку, сгенерированный формой, которая работает:
curl 'http://localhost:8000/api/v1/reset/Mw/set-password/' -H 'Cookie: meteor_login_token=OG2fh2iVTkn5AOujhdaBXCsetV-CQ1lS6ZLdtrtzFYC; csrftoken=uSEF8NQB0lUpimwfQcOWLt118igo0bQq2gbpTaGq7zvgQMeF4oM2cu3ZwfgmuDOa; sessionid=39awyoab3wouvxmacbzbxez2hrfoa498' -H 'Origin: http://localhost:8000' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http://localhost:8000/api/v1/reset/Mw/set-password/' -H 'Connection: keep-alive' --data 'csrfmiddlewaretoken=ASbYGmwXWOTKagND1hWHK0DQt5Qo9MPq8gIIrJmM32uBIGv3ftUNb1FOR2QmDeNa&new_password1=sometext&new_password2=sometext' --compressed
Вот мой запрос на выборку, который завершается с ошибкой 'Ссылка для сброса пароля была недействительной, возможно, потому что она уже использовалась.Пожалуйста, запросите новый сброс пароля. ':
curl 'http://127.0.0.1:3000/api/v1/reset/Mw/set-password/' -H 'Origin: http://127.0.0.1:3000' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml' -H 'Referer: http://127.0.0.1:3000/reset/Mw/52l-69686a35c125eb3eafd0/' -H 'Cookie: tabstyle=html-tab; csrftoken=8H5chA6Pq5fw1UkRjKWg91EMSK4A91NrKE4TAODlAvPJGfGhQjCDuEYe8Xc1fEN9' -H 'Connection: keep-alive' -H 'X-CSRFToken: 8H5chA6Pq5fw1UkRjKWg91EMSK4A91NrKE4TAODlAvPJGfGhQjCDuEYe8Xc1fEN9' --data 'uid=Mw&csrfmiddlewaretoken=8H5chA6Pq5fw1UkRjKWg91EMSK4A91NrKE4TAODlAvPJGfGhQjCDuEYe8Xc1fEN9&password=sometext&password_confirm=sometext&' --compressed
Вероятно, проблема связана с токеном csrf, который я генерирую в соответствии с этими инструкциями .
urls.py:
# api/urls.py
from django.urls import include, path
from django.contrib.auth import views
urlpatterns = [
path('rest-auth/', include('rest_auth.urls')),
path('rest-auth/registration/', include('rest_auth.registration.urls')),
path('users/', include('users.urls')),
path('password_change/', views.PasswordChangeView.as_view(), name='password_change'),
path('password_change/done/', views.PasswordChangeDoneView.as_view(), name='password_change_done'),
path('password_reset/', views.PasswordResetView.as_view(), name='password_reset'),
path('password_reset/done/', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
Вот функция генерации cookie:
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = $.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
Мой конструктор запросов на выборку:
fetch(`/api/v1/reset/${data.uid}/set-password/`,
{ credentials: 'include', 'method': 'POST', mode: 'same-origin',
headers: {
'Accept': 'text/html,application/xhtml+xml,application/xml',
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': csrftoken
}, 'body': body })
Моя форма имеет скрытый ввод стот же токен:
<input type="hidden" name="csrfmiddlewaretoken" value={csrftoken} />
<button type="submit" className="btn btn-primary">
Set new password
</button>
Все, что я читал о запросах django csrf, говорит о том, что cookie в заголовке и cookie в данных формы должны совпадать.Однако значения, установленные в рабочем запросе, сгенерированном формой по умолчанию, не совпадают друг с другом.Я также вижу, что рабочий запрос включает идентификатор сеанса, но я не знаю, важно ли это.
Кто-нибудь может мне помочь, пожалуйста, чтобы понять, какие значения мне нужно отправить в моем запросе на выборку?
Или, если есть какой-то другой простой способ создать страницу сброса пароля в React, которую я пропустил, пожалуйста, укажите мне правильное направление!