Django REST-Auth密码重置 [英] Django REST-Auth Password Reset

查看:394
本文介绍了Django REST-Auth密码重置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对可用的django中间件完全感到困惑:

I am completely confused by the django middleware available:

我只想使用<$ c来运行密码重置(以及以后的密码更改)功能。 $ c> django ,后端为 rest_auth ,前端为Vue。

I simply want to get password-reset (and later password-change) functionality running, using django with rest_auth on the backend and Vue on the frontend.

到目前为止,我已经完成了 CustomPasswordResetView

So far I have made a CustomPasswordResetView:

# project/accounts/views.py
from rest_auth.views import PasswordResetView

class CustomPasswordResetView(PasswordResetView):
pass



序列化器



CustomPasswordResetSerializer

# project/accounts/serializers.py
from rest_auth.serializers import PasswordResetSerializer

class CustomPasswordResetSerializer(PasswordResetSerializer):
    email = serializers.EmailField()
    password_reset_form_class = ResetPasswordForm

    def validate_email(self, value):
        # Create PasswordResetForm with the serializer
        self.reset_form = self.password_reset_form_class(data=self.initial_data)
        if not self.reset_form.is_valid():
            raise serializers.ValidationError(self.reset_form.errors)

        ###### FILTER YOUR USER MODEL ######
        if not get_user_model().objects.filter(email=value).exists():
            raise serializers.ValidationError(_('Invalid e-mail address'))

        return value

    def save(self):
        request = self.context.get('request')
        # Set some values to trigger the send_email method.
        opts = {
            'use_https': request.is_secure(),
            'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
            'request': request,
        }
        opts.update(self.get_email_options())
        self.reset_form.save(**opts)



Settings.py



settings.py 中,我有这些字段,这似乎与我的问题有关:

Settings.py

In the settings.py I have these fields, which seem relevant to me for my problem:

# project/vuedj/settings.py
REST_AUTH_SERIALIZERS = {
    "USER_DETAILS_SERIALIZER": "accounts.serializers.CustomUserDetailsSerializer",
    "LOGIN_SERIALIZER": "accounts.serializers.CustomUserLoginSerializer",
    "PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer"
}

(完整的 settings.py 附加在底部)

我的网址是急于捕获我的API请求以发送密码重置电子邮件:

My urls already catch my API request in order to send the Password-Reset Email:

# project/vuedj/urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('api.urls')),
    path('accounts/', include('allauth.urls')),
    path('', api_views.index, name='home')
]



# project/api/urls.py
urlpatterns = [
    path('auth/', include('accounts.urls')),
    # other paths...
]



# project/accounts/urls.py
urlpatterns = [
    path('', acc_views.UserListView.as_view(), name='user-list'),
    path('login/', acc_views.UserLoginView.as_view(), name='login'),
    path('logout/', acc_views.UserLogoutView.as_view(),  name='logout'),
    path('register/', acc_views.CustomRegisterView.as_view(),  name='register'),
    path('reset-password/', acc_views.CustomPasswordResetView.as_view(), name='reset-password'),
    path('reset-password-confirm/', acc_views.CustomPasswordResetConfirmView.as_view(), name='reset-password-confirm'),
    path('<int:pk>/', acc_views.UserDetailView.as_view(), name='user-detail')
]



带有PW重置令牌生成器的电子邮件



CustomPasswordReset视图最终将生成带有精美的pw-reset链接的精美电子邮件。该链接有效,当我单击它时,我可以通过allauth模板完美地重置密码。

Email with PW-Reset Token Generator

The CustomPasswordReset view will eventually generate a nice email with a nice pw-reset link. The link is valid, as I click it, I can reset the password through the allauth templates perfectly.

rest-auth使用此代码(间接)生成密码。重置令牌:

This code is used by rest-auth (indirectly) to generate the reset-token:

# project/.venv/Lib/site-packages/allauth/account/forms.py
def save(self, request, **kwargs):
    current_site = get_current_site(request)
    email = self.cleaned_data["email"]
    token_generator = kwargs.get("token_generator",
                                 default_token_generator)

    for user in self.users:

        temp_key = token_generator.make_token(user)

        # save it to the password reset model
        # password_reset = PasswordReset(user=user, temp_key=temp_key)
        # password_reset.save()

        # send the password reset email
        path = reverse("account_reset_password_from_key",
                       kwargs=dict(uidb36=user_pk_to_url_str(user),
                                   key=temp_key))
        url = build_absolute_uri(
            request, path)

        context = {"current_site": current_site,
                   "user": user,
                   "password_reset_url": url,
                   "request": request}

        if app_settings.AUTHENTICATION_METHOD \
                != AuthenticationMethod.EMAIL:
            context['username'] = user_username(user)
        get_adapter(request).send_mail(
            'account/email/password_reset_key',
            email,
            context)
    return self.cleaned_data["email"]

上面的代码中使用了PasswordResetTokenGenerator

# project/.venv/Lib/site-packages/django/contrib/auth/tokens.py
class PasswordResetTokenGenerator:
        """
        Strategy object used to generate and check tokens for the password
        reset mechanism.
        """
        key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
        secret = settings.SECRET_KEY

        def make_token(self, user):
                """
                Return a token that can be used once to do a password reset
                for the given user.
                """
                return self._make_token_with_timestamp(user, self._num_days(self._today()))

        def check_token(self, user, token):
                """
                Check that a password reset token is correct for a given user.
                """
                if not (user and token):
                        return False
                # Parse the token
                try:
                        ts_b36, hash = token.split("-")
                except ValueError:
                        return False

                try:
                        ts = base36_to_int(ts_b36)
                except ValueError:
                        return False

                # Check that the timestamp/uid has not been tampered with
                if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
                        return False

                # Check the timestamp is within limit. Timestamps are rounded to
                # midnight (server time) providing a resolution of only 1 day. If a
                # link is generated 5 minutes before midnight and used 6 minutes later,
                # that counts as 1 day. Therefore, PASSWORD_RESET_TIMEOUT_DAYS = 1 means
                # "at least 1 day, could be up to 2."
                if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
                        return False

                return True

The上面的类将由 rest_auth PasswordResetView 调用:

The classes above will be called by the rest_auth PasswordResetView:

# project/.venv/Lib/site-packages/rest_auth/views.py
class PasswordResetView(GenericAPIView):
        """
        Calls Django Auth PasswordResetForm save method.

        Accepts the following POST parameters: email
        Returns the success/fail message.
        """
        serializer_class = PasswordResetSerializer
        permission_classes = (AllowAny,)

        def post(self, request, *args, **kwargs):
                # Create a serializer with request.data
                serializer = self.get_serializer(data=request.data)
                serializer.is_valid(raise_exception=True)

                serializer.save() # <----- Code from above (TokenGenerator) will be called inside this .save() method
                # Return the success message with OK HTTP status
                return Response(
                        {"detail": _("Password reset e-mail has been sent.")},
                        status=status.HTTP_200_OK
                )

如您所见,令牌生成器将返回带有令牌的 uidb36
当用户确认密码重置时,它还假定 uidb36
生成的令牌(例如,生成的邮件中的完整链接)如下所示:

As you can see, the Tokengenerator will return a uidb36 with the token. It also assumes a uidb36 when the user would confirm the password-reset. A generated token (for example the full link in the generated mail) would look like this:

http://localhost:8000/accounts/password/reset/key/16-52h-42b222e6dc30690b2e91/

其中 16 是基数为36的用户ID( uidb36 ),我尚不知道 52h 表示,但我认为令牌的第三部分是令牌本身( 42b222e6dc30690b2e91

Where 16 is the user id in base 36 (uidb36), I do not yet know what 52h means, but I assume, the third part of the token is the token itself (42b222e6dc30690b2e91)

我被困在这里。
API端点 = https://django-rest-auth.readthedocs.io/en/latest/index.html rel = noreferrer> Rest-Auth-Framework 说:

I am stuck here. The API-Endpoints of the Rest-Auth-Framework say:


/ rest-auth / password / reset / confirm /(POST)

uid

令牌

new_password1

new_password2

当我发送对象时,例如:

And when I send an object e.g:

{
    uid: '16', // TODO maybe I have to convert it to base10...
    token: '42b222e6dc30690b2e91',
    new_password1: 'test123A$',
    new_password2: 'test123A$'
}



通过我的api到 http:// localhost:8000 / api / v1 / auth / reset-password / 上面的对象位于 axios 发布请求的正文中,我的 CustomPasswordRes etConfirmView 像预期的那样被触发,它也是 rest_auth PasswordResetConfirmView 的子类,因此执行以下代码:

via my api to http://localhost:8000/api/v1/auth/reset-password/ with the object above in the body of an axios-post request, my CustomPasswordResetConfirmView is triggered like expected, which is also just a Subclass of PasswordResetConfirmView from rest_auth, so this code is executed:

# project/.venv/Lib/site-packages/rest_auth/views.py
class PasswordResetConfirmView(GenericAPIView):
        """
        Password reset e-mail link is confirmed, therefore
        this resets the user's password.

        Accepts the following POST parameters: token, uid,
                new_password1, new_password2
        Returns the success/fail message.
        """
        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.")}
                )

该行 serializer.is_valid(raise_exception = True)将调用 Serializer(BaseSerializer)的 run_validation rest_framework 中的code>。
这将进一步使用 PasswordResetConfirmSerializer rest_auth

The line serializer.is_valid(raise_exception=True) will call run_validation of the Serializer(BaseSerializer) of the rest_framework. This will further use the PasswordResetConfirmSerializer of rest_auth:

# project/.venv/Lib/site-packages/rest_auth/serializers.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']))
                        self.user = UserModel._default_manager.get(pk=uid)
                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

最后您可以看到,该类我希望用户标识使用uidb64而不是uidb36,我什至不希望知道令牌格式是否与此处期望的匹配。

And as you can finally see, this class is expecting a uidb64 instead of a uidb36 for the user id, and I do not even want to know whether the token-format is anyhow matching what is expected here.

I真的找不到关于如何正确设置 rest_auth 的完整密码重置过程的优质文档:我可以使用电子邮件,但对我来说, rest_auth 会生成错误的tok zh_cn / reset-link以获取用户实际期望返回的内容。

I really cannot find good documentation about how to setup rest_auth properly for the full password-reset process: I got the email working, but for me it seems, rest_auth would generate a wrong token/reset-link for what it is actually expecting back from the user.

我相信,密码重置确认过程以正确的后端代码结束,而电子邮件/令牌生成过程却一团糟。

I believe, the password-reset-confirmation process is ending in the correct backend-code, while the email/token-generation is messed up.

我要做的就是检索 uid 和一个令牌,我可以将其发送回django rest-auth,以便用户重置密码。
当前,似乎这些uid和令牌是由一个库创建的,而又由另一个图书馆使用的,它们期望并创建不同格式的Token和uid?

All I want is to retrieve a uid and a token which I can send back to django rest-auth in order to let users reset their passwords. Currently, it seems that these uids and tokens are created by one library and consumed by another library which both expect and create different formats of tokens and uids?

这是我完整的 settings.py

# project/vuedj/settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
SECRET_KEY = persisted_settings.SECRET_KEY
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
CORS_ORIGIN_ALLOW_ALL = True
CORS_URLS_REGEX = r'^/api/.*$'
CORS_ALLOW_CREDENTIALS = True

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'rest_framework',
    'rest_framework.authtoken',
    'corsheaders',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.github',
    'rest_auth',
    'rest_auth.registration',
    'sceneries',
    'accounts',
    'api',
    'app',
]

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = 'app-messages'
SITE_ID = 1

AUTH_USER_MODEL = 'accounts.User'
ACCOUNT_USER_MODEL_USERNAME_FIELD = 'username'
ACCOUNT_AUTHENTICATION_METHOD = 'username_email'

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'none'
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = True
ACCOUNT_USER_EMAIL_FIELD = 'email'
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_FORMS = {"login": "accounts.forms.UserLoginForm"}
LOGIN_REDIRECT_URL = 'home'
LOGIN_URL = 'api/v1/accounts/login/'

CSRF_COOKIE_NAME = "csrftoken"

REST_AUTH_SERIALIZERS = {
    "USER_DETAILS_SERIALIZER": "accounts.serializers.CustomUserDetailsSerializer",
    "LOGIN_SERIALIZER": "accounts.serializers.CustomUserLoginSerializer",
    "PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer"
}

REST_AUTH_REGISTER_SERIALIZERS = {
    "REGISTER_SERIALIZER": "accounts.serializers.CustomRegisterSerializer",
}

# Following is added to enable registration with email instead of username
AUTHENTICATION_BACKENDS = (
    # Needed to login by username in Django admin, regardless of `allauth`
    "django.contrib.auth.backends.ModelBackend",
    # `allauth` specific authentication methods, such as login by e-mail
    "allauth.account.auth_backends.AuthenticationBackend",
)

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    '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',
]

ROOT_URLCONF = 'vuedj.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            'templates/',
            'templates/emails/'
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'vuedj.wsgi.application'

try:
        DATABASES = persisted_settings.DATABASES
except AttributeError:
        DATABASES = {
                'default': {
                        'ENGINE': 'django.db.backends.sqlite3',
                        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
                }
        }

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
STATIC_ROOT = os.path.join(BASE_DIR, '../staticfiles/static')
MEDIA_ROOT = os.path.join(BASE_DIR, '../staticfiles/mediafiles')
STATIC_URL = '/static/'
MEDIA_URL = '/media/'

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

NOSE_ARGS = [
    '--with-coverage',
    '--cover-package=app',  # For multiple apps use '--cover-package=foo, bar'
]


推荐答案

幸运的是,我发现了一个不错的图书馆,这使我今天的生活如此轻松:

Luckily, I found a nice library which made my life so easy today:

https://github.com/anx-ckreuzberger/django-rest-passwordreset

pip install django-rest-passwordreset

让它像这样工作:


  1. 按照其网站上的说明进行操作。

我的 accounts / urls.py 现在具有以下路径:

My accounts/urls.py now has the following paths:

# project/accounts/urls.py
from django.urls import path, include
from . import views as acc_views

app_name = 'accounts'
urlpatterns = [
    path('', acc_views.UserListView.as_view(), name='user-list'),
    path('login/', acc_views.UserLoginView.as_view(), name='login'),
    path('logout/', acc_views.UserLogoutView.as_view(), name='logout'),
    path('register/', acc_views.CustomRegisterView.as_view(), name='register'),
    # NEW: custom verify-token view which is not included in django-rest-passwordreset
    path('reset-password/verify-token/', acc_views.CustomPasswordTokenVerificationView.as_view(), name='password_reset_verify_token'),
    # NEW: The django-rest-passwordreset urls to request a token and confirm pw-reset
    path('reset-password/', include('django_rest_passwordreset.urls', namespace='password_reset')),
    path('<int:pk>/', acc_views.UserDetailView.as_view(), name='user-detail')
]

然后我还为我的Custo添加了一些TokenSerializer mTokenVerification:

Then I also added a little TokenSerializer for my CustomTokenVerification:

# project/accounts/serializers.py
from rest_framework import serializers

class CustomTokenSerializer(serializers.Serializer):
    token = serializers.CharField()

然后我在先前派生的 CustomPasswordResetView 中添加了信号接收器,现在不再从派生rest_auth.views.PasswordResetView AND 添加了新视图 CustomPasswordTokenVerificationView

Then I added a Signal Receiver in the previous derived CustomPasswordResetView, which now is no longer derived from rest_auth.views.PasswordResetView AND added a new view CustomPasswordTokenVerificationView:

# project/accounts/views.py
from django.dispatch import receiver
from django_rest_passwordreset.signals import reset_password_token_created
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from vuedj.constants import site_url, site_full_name, site_shortcut_name
from rest_framework.views import APIView
from rest_framework import parsers, renderers, status
from rest_framework.response import Response
from .serializers import CustomTokenSerializer
from django_rest_passwordreset.models import ResetPasswordToken
from django_rest_passwordreset.views import get_password_reset_token_expiry_time
from django.utils import timezone
from datetime import timedelta

class CustomPasswordResetView:
    @receiver(reset_password_token_created)
    def password_reset_token_created(sender, reset_password_token, *args, **kwargs):
        """
          Handles password reset tokens
          When a token is created, an e-mail needs to be sent to the user
        """
        # send an e-mail to the user
        context = {
            'current_user': reset_password_token.user,
            'username': reset_password_token.user.username,
            'email': reset_password_token.user.email,
            'reset_password_url': "{}/password-reset/{}".format(site_url, reset_password_token.key),
            'site_name': site_shortcut_name,
            'site_domain': site_url
        }

        # render email text
        email_html_message = render_to_string('email/user_reset_password.html', context)
        email_plaintext_message = render_to_string('email/user_reset_password.txt', context)

        msg = EmailMultiAlternatives(
            # title:
            "Password Reset for {}".format(site_full_name),
            # message:
            email_plaintext_message,
            # from:
            "noreply@{}".format(site_url),
            # to:
            [reset_password_token.user.email]
        )
        msg.attach_alternative(email_html_message, "text/html")
        msg.send()


class CustomPasswordTokenVerificationView(APIView):
    """
      An Api View which provides a method to verifiy that a given pw-reset token is valid before actually confirming the
      reset.
    """
    throttle_classes = ()
    permission_classes = ()
    parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
    renderer_classes = (renderers.JSONRenderer,)
    serializer_class = CustomTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        token = serializer.validated_data['token']

        # get token validation time
        password_reset_token_validation_time = get_password_reset_token_expiry_time()

        # find token
        reset_password_token = ResetPasswordToken.objects.filter(key=token).first()

        if reset_password_token is None:
            return Response({'status': 'invalid'}, status=status.HTTP_404_NOT_FOUND)

        # check expiry date
        expiry_date = reset_password_token.created_at + timedelta(hours=password_reset_token_validation_time)

        if timezone.now() > expiry_date:
            # delete expired token
            reset_password_token.delete()
            return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND)

        # check if user has password to change
        if not reset_password_token.user.has_usable_password():
            return Response({'status': 'irrelevant'})

        return Response({'status': 'OK'})

现在,我的前端将提供一个请求pw的选项-reset链接,因此前端将向django发送发布请求,如下所示:

Now my frontend will provide an option to request the pw-reset link, so the frontend will send a post request to django like this:

// urls.js
const SERVER_URL = 'http://localhost:8000/' // FIXME: change at production (https and correct IP and port)
const API_URL = 'api/v1/'
const API_AUTH = 'auth/'
API_AUTH_PASSWORD_RESET = API_AUTH + 'reset-password/'


// api.js
import axios from 'axios'
import urls from './urls'

axios.defaults.baseURL = urls.SERVER_URL + urls.API_URL
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.defaults.xsrfCookieName = 'csrftoken'

const api = {
    get,
    post,
    patch,
    put,
    head,
    delete: _delete
}

function post (url, request) {
    return axios.post(url, request)
        .then((response) => Promise.resolve(response))
        .catch((error) => Promise.reject(error))
}


// user.service.js
import api from '@/_api/api'
import urls from '@/_api/urls'

api.post(`${urls.API_AUTH_PASSWORD_RESET}`, email)
    .then( /* handle success */ )
    .catch( /* handle error */ )

所创建的电子邮件将包含这样的链接:

And the created email will contain a link like this:

Click the link below to reset your password.

localhost:8000/password-reset/4873759c229f17a94546a63eb7c3d482e73983495fa40c7ec2a3d9ca1adcf017

...其中没有在django-urls中被故意定义!
Django将让每个未知的URL都通过,而vue路由器将决定该URL是否有意义。
然后,我让前端发送令牌以查看其是否有效,以便用户可以查看该令牌是否已被使用,过期或其他...

... which is not defined in the django-urls by intention! Django will let every unknown url pass through and the vue router will decide if the url makes sense or not. Then I let the frontend send the token to see if it is valid, so the user can already see if the token is already used, expired, or whatever...

// urls.js
const API_AUTH_PASSWORD_RESET_VERIFY_TOKEN = API_AUTH + 'reset-password/verify-token/'

// users.service.js
api.post(`${urls.API_AUTH_PASSWORD_RESET_VERIFY_TOKEN}`, pwResetToken)
    .then( /* handle success */ )
    .catch( /* handle error */ )

现在,用户将通过Vue或密码输入获得错误消息fields, where they can finally reset the password, which will be sent by the frontend like this:

Now the user will get an error message through Vue, or password-input fields, where they can finally reset the password, which will be sent by the frontend like this:

// urls.js
const API_AUTH_PASSWORD_RESET_CONFIRM = API_AUTH + 'reset-password/confirm/'

// users.service.js
api.post(`${urls.API_AUTH_PASSWORD_RESET_CONFIRM}`, {
    token: state[token], // (vuex state)
    password: state[password] // (vuex state)
})
.then( /* handle success */ )
.catch( /* handle error */ )

This is the main code. I used custom vue routes to decouple the django rest-endpoints from the frontend visible routes. The rest is done with api requests and handling their responses.

This is the main code. I used custom vue routes to decouple the django rest-endpoints from the frontend visible routes. The rest is done with api requests and handling their responses.

Hope this helps anybody who will have struggles like me in the future.

Hope this helps anybody who will have struggles like me in the future.

这篇关于Django REST-Auth密码重置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆