reactjs - 密码重置链接未重定向到网站
问题描述
我正在尝试使用 django rest 框架在我的 React 应用程序中实现密码重置功能。我正在使用rest_auth。
问题:一旦我尝试从网站重置密码,它会向电子邮件发送密码重置链接。但是在单击该链接时,它会重定向到 DRF 默认密码重置页面,而不是我网站所需的密码重置页面。当我从 localhost 尝试它时它工作正常。但是一旦部署到 Heroku,它就不起作用了。
一些观察: 考虑下面我通过电子邮件收到的链接
https://mysite.herokuapp.com/password/reset/confirm/MQ/5a1-f42302b192f38cf29a3/
如果我强制删除 URL 中的尾部斜杠 ( / ),它会重定向到我的网站密码重置页面,然后它会按预期工作。我尝试从 React 的 axios 请求中删除斜杠,但它不起作用。
我必须在 Heroku 上配置任何东西吗?
这是我的密码重置页面的 React 路线
<Route path='/password/reset/confirm/:uid/:token/' component={PasswordRestConfirm} />
下面的这个动作在提交表单时触发。
export const setNewPassword = (new_password1, new_password2, uid, token) => (dispatch, getState) => {
dispatch({ type: SET_NEW_PASSWORD_START });
var bodyFormData = new FormData();
bodyFormData.append('new_password1', new_password1);
bodyFormData.append('new_password2', new_password2);
bodyFormData.append('uid', uid);
bodyFormData.append('token', token);
axios
.post(`https://mysite.herokuapp.com/password/reset/confirm/${uid}/${token}/`, bodyFormData)
.then(res => {
dispatch(createMessage({ passwordChangeSuccess: 'Your password was set successfully' }));
dispatch({
type: SET_NEW_PASSWORD,
payload: res.data
});
})
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: SET_NEW_PASSWORD_FAIL
});
});
};
设置.py
ALLOWED_HOSTS = ['mysite.herokuapp.com']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'corsheaders',
'rest_auth',
'rest_auth.registration',
'rest_framework',
'rest_framework.authtoken',
# Some other app
]
SITE_ID = 1
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
}
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER': 'accounts.api.serializers.PasswordResetSerializer',
'PASSWORD_RESET_CONFIRM_SERIALIZER ': 'accounts.api.serializers.PasswordResetConfirmSerializer',
}
REST_SESSION_LOGIN = True
CORS_ORIGIN_ALLOW_ALL = True
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_AUTHENTICATION_METHOD = 'username'
# ***********Email settings **************
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = os.environ['EMAIL_USER']
EMAIL_HOST_PASSWORD = os.environ['EMAIL_PASS']
网址.py
urlpatterns = [
path('password/reset/confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
]
视图.py
class PasswordResetConfirmView(GenericAPIView):
serializer_class = PasswordResetConfirmSerializer
permission_classes = (AllowAny,)
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
{"detail": _("Password has been reset with the new password.")}
)
序列化程序.py
class PasswordResetConfirmSerializer(serializers.Serializer):
"""
Serializer for requesting a password reset e-mail.
"""
new_password1 = serializers.CharField(max_length=128)
new_password2 = serializers.CharField(max_length=128)
uid = serializers.CharField()
token = serializers.CharField()
set_password_form_class = SetPasswordForm
def custom_validation(self, attrs):
pass
def validate(self, attrs):
self._errors = {}
# Decode the uidb64 to uid to get User object
try:
uid = force_text(uid_decoder(attrs['uid']))
print(uid)
self.user = UserModel._default_manager.get(pk=uid)
print(self.user)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
raise ValidationError({'uid': ['Invalid value']})
self.custom_validation(attrs)
# Construct SetPasswordForm instance
self.set_password_form = self.set_password_form_class(
user=self.user, data=attrs
)
if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors)
if not default_token_generator.check_token(self.user, attrs['token']):
raise ValidationError({'token': ['Invalid value']})
return attrs
def save(self):
return self.set_password_form.save()
解决方案
推荐阅读
- python - Django Rest Framework - 在 python 客户端中反序列化响应时重用模型逻辑
- reactjs - 使 history.push 在 React app.tsx 中可用
- sql - 为什么datatable会改变日期的格式
- python - 在 python 中删除目录几乎总是会导致文件夹“锁定”并且由于权限错误而无法删除
- reflection - 如何在 Mvx.IoCProvider.Register 中提供类似 OnActivate(在 Autofac 中)的功能
- c# - 将 TempData 传递给 ActionFilter RedirectToAction
- elasticsearch - 在不同字段中按空格分隔的查询字符串搜索
- sql - SQL 文本匹配(where 子句中的转换)
- c# - 使用适当的编码约定适应用于脱盐的 JSON 文件中的内容
- azure - 通过 AZ CLI 将本地 docker tarfile 导入 Azure ACR?