Django结合React,如何通过发送电子邮件来重置用户密码

4

我正在使用Django和React,实现一种当用户忘记密码时重置密码的方法。我的基本想法是:

1) 用户提供他们的电子邮件地址

2) 使用SendGrid api向他们的电子邮件地址发送包含重置密码链接的电子邮件

3) 用户输入新密码以重置密码

下面是我的序列化器(serializers),视图(views),URL和React代码

//views.py
class PasswordResetConfirmSerializer(serializers.Serializer):
    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 = {}
        try:
            self.user = UserModel._default_manager.get(pk=attrs['uid'])
        except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
            raise ValidationError({'uid': ['Invalid value']})
        self.custom_validation(attrs)
        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)
        return attrs
    def save(self):
        return self.set_password_form.save()

// serializers.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.")}
       )

//urls.py
path('api/passwordreset/confirm/',views.PasswordResetConfirmView.as_view(), name = 'password_reset_confirm')

// React 
    const config = {
    headers: {
      "Content-Type": "application/json"
      }
    };

    const body = JSON.stringify({ 
        new_password1: this.state.new_password,
        new_password2: this.state.confirm_password,
        uid: this.state.fetched_data.pk,
        token: this.state.fetched_data.token
    })

    axios.post(API_URL + 'users/api/passwordreset/confirm/', body, config)

我的重置密码功能本身是正常工作的。但我在这里遇到的主要问题是,重置密码API需要'uid'和'token'。为了获得这两个值,用户必须已经登录,这毫无意义,因为他们忘记了密码,或者调用一个API来获取'uid'和'token'。我尝试了下面的方法来获取这两个值:

// views.py
class CustomObtainAuthToken(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        response = super(CustomObtainAuthToken, self).post(request, *args, **kwargs)
        token = Token.objects.get(key=response.data['token'])
        return Response({'token': token.key, 'id': token.user_id})

// urls.py
path('api/authenticate/', CustomObtainAuthToken.as_view())

// React 
const body = { 
    password: 'mike',
    username: 'Abcd1234'
  }

  await axios.post(API_URL + 'users/api/authenticate/', body)

该函数确实返回了正确的“uid”和“token”,但问题是我只得到了用户的电子邮件地址。我无法获取密码和用户名以调用此API。因此,我不太确定该如何处理。
有人可以向我展示使其正常工作的正确方法吗?非常感谢。
1个回答

8
首先,您可以从请求密码重置流程的用户电子邮件中获取uid。其次,此令牌与经过身份验证的用户的令牌不同。该令牌可以使用Django的 default_token_generator 生成。

以下是通常的流程:

  1. 用户提供email
  2. 前端使用该email调用API(例如/api/password_reset/
  3. a)API确定是哪个useremail,因此获得一个 uid
    b)为该user生成一个token
    c)发送一封带有URL的电子邮件。 URL必须包含uidtoken作为其一部分(例如:https://example.com/password-reset-confirm/<uid>/<token>
  4. 用户单击此链接后,显示一个前端页面,要求输入新的password注意:此URL包含之前获得的uidtoken
  5. 用户提供新的password
  6. 前端使用新提供的password和之前获取的uidtoken(作为URL的一部分)调用API(例如/api/password_reset_confirm/
  7. API接收uidtoken和新的password
    a)检查uidtoken是否有效(即token是否与其先前为该uid的同一个user生成的令牌相匹配)
    b)设置该uiduser的新密码
    c)可选择将用户注销系统

由于您正在使用DRF,因此请参考名为Djoser的身份验证库的实现。这可能是一个很好的学习经验。


嗨@mehamasum,能否请您查看一下这个问题。我找不到任何解决方案。 https://stackoverflow.com/questions/58093916/password-reset-link-not-redirecting-to-website - ConAra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接