Django Rest Framework сброс пароля
Я следую учебнику на YouTube и задаюсь вопросом, зачем нам нужен PasswordTokenCheckAPI в views.py, ведь мы все равно потом проверяем uidb64 и токен снова в SetNewPasswordAPIView (в serialiser.is_valid() мы также проверяем, действительны ли токен и uidb64). Можем ли мы просто дать url на страницу сброса пароля прямо в электронном письме и проверить все позже, когда пользователь отправит запрос на сброс пароля?
class RequestPasswordResetEmail(generics.GenericAPIView):
serializer_class = ResetPasswordEmailRequestSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
email = request.data.get('email', '')
if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
uidb64 = urlsafe_base64_encode(smart_bytes(user.id))
token = PasswordResetTokenGenerator().make_token(user)
current_site = get_current_site(
request=request).domain
relativeLink = reverse(
'password-reset-confirm', kwargs={'uidb64': uidb64, 'token': token})
redirect_url = request.data.get('redirect_url', '')
absurl = 'http://'+current_site + relativeLink
email_body = 'Hello, \n Use link below to reset your password \n' + \
absurl+"?redirect_url="+redirect_url
data = {'email_body': email_body, 'to_email': user.email,
'email_subject': 'Reset your passsword'}
Util.send_email(data)
return Response({'success': 'We have sent you a link to reset your password'}, status=status.HTTP_200_OK)
class PasswordTokenCheckAPI(generics.GenericAPIView):
serializer_class = SetNewPasswordSerializer
def get(self, request, uidb64, token):
redirect_url = request.GET.get('redirect_url')
try:
id = smart_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(id=id)
if not PasswordResetTokenGenerator().check_token(user, token):
if len(redirect_url) > 3:
return CustomRedirect(redirect_url+'?token_valid=False')
else:
return CustomRedirect(os.environ.get('FRONTEND_URL', '')+'?token_valid=False')
if redirect_url and len(redirect_url) > 3:
return CustomRedirect(redirect_url+'?token_valid=True&message=Credentials Valid&uidb64='+uidb64+'&token='+token)
else:
return CustomRedirect(os.environ.get('FRONTEND_URL', '')+'?token_valid=False')
except DjangoUnicodeDecodeError as identifier:
try:
if not PasswordResetTokenGenerator().check_token(user):
return CustomRedirect(redirect_url+'?token_valid=False')
except UnboundLocalError as e:
return Response({'error': 'Token is not valid, please request a new one'}, status=status.HTTP_400_BAD_REQUEST)
class SetNewPasswordAPIView(generics.GenericAPIView):
serializer_class = SetNewPasswordSerializer
def patch(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response({'success': True, 'message': 'Password reset success'}, status=status.HTTP_200_OK)
и в serialiser.py
class ResetPasswordEmailRequestSerializer(serializers.Serializer):
email = serializers.EmailField(min_length=2)
redirect_url = serializers.CharField(max_length=500, required=False)
class Meta:
fields = ['email']
class SetNewPasswordSerializer(serializers.Serializer):
password = serializers.CharField(
min_length=6, max_length=68, write_only=True)
token = serializers.CharField(
min_length=1, write_only=True)
uidb64 = serializers.CharField(
min_length=1, write_only=True)
class Meta:
fields = ['password', 'token', 'uidb64']
def validate(self, attrs):
try:
password = attrs.get('password')
token = attrs.get('token')
uidb64 = attrs.get('uidb64')
id = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(id=id)
if not PasswordResetTokenGenerator().check_token(user, token):
raise AuthenticationFailed('The reset link is invalid', 401)
user.set_password(password)
user.save()
return (user)
except Exception as e:
raise AuthenticationFailed('The reset link is invalid', 401)
return super().validate(attrs)