代码之家  ›  专栏  ›  技术社区  ›  ElectRocnic

django rest auth密码重置

  •  0
  • ElectRocnic  · 技术社区  · 6 年前

    我完全被可用的Django中间件所迷惑:

    我只想让密码重置(以及以后的密码更改)功能运行,使用 django 具有 rest_auth 在后端,Vue在前端。

    步骤1:通过邮件请求重置链接

    意见

    到目前为止,我已经 CustomPasswordResetView :

    # project/accounts/views.py
    from rest_auth.views import PasswordResetView
    
    class CustomPasswordResetView(PasswordResetView):
    pass
    

    串行器

    和A 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)
    

    设置Py

    settings.py 我有这些领域,这似乎与我的问题有关:

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

    (完成) 设置Py 附在底部)

    URL模式

    我的URL已捕获我的API请求,以便发送密码重置电子邮件:

    # 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模板完美地重置密码。

    REST AUTH(间接)使用此代码生成重置令牌:

    # 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
    

    上面的类将由 赖斯塔 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 当用户确认密码重置时。 生成的令牌(例如生成邮件中的完整链接)如下所示:

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

    在哪里? 16 用户ID是否以36为基数( UIDB36 )我还不知道 52h 意思是,但我假设,令牌的第三部分是令牌本身( 42b222e6dc30690b2e91 )

    步骤2:将令牌发送到后端(又称“用户单击链接”)。

    我被困在这里。 这个 API-Endpoints Rest-Auth-Framework 说:

    /rest auth/password/reset/confirm/(post)
    uid
    token
    new_password1
    new_password2

    当我发送一个对象时,例如:

    {
        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 -发布请求,我的 CustomPasswordResetConfirmView 像预期的那样触发,它也是 PasswordResetConfirmView 赖斯塔 ,因此执行此代码:

    # 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) 将呼叫 run_validation Serializer(BaseSerializer) rest_framework . 这将进一步使用 PasswordResetConfirmSerializer 属于 赖斯塔 :

    # 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
    

    正如您最后看到的,这个类期望用户ID是一个uidb64而不是uidb36,我甚至不想知道令牌格式是否与这里期望的格式匹配。

    我真的找不到关于如何设置的好文档 赖斯塔 完全密码重置过程:我的电子邮件正常工作,但对我来说, 赖斯塔 将生成错误的令牌/重置链接,以满足用户的实际期望。

    总结

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

    我只想找回 UID 和A 令牌 我可以发送回django rest auth,让用户重置密码。 目前,这些uid和tokens似乎是由一个库创建的,并由另一个库使用,这两个库都期望并创建不同格式的tokens和uid?

    事先谢谢!

    设置Py

    这是我的全部 设置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'
    ]
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   ElectRocnic    6 年前

    幸运地 我找到了一个很好的图书馆,让我今天的生活变得如此轻松:

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

    pip install django-rest-passwordreset

    让它像这样工作:

    1. 遵循他们网站上的说明。

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

    # 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')
    ]
    

    然后我还为我的customTokenVerification添加了一个小的令牌序列化程序:

    # project/accounts/serializers.py
    from rest_framework import serializers
    
    class CustomTokenSerializer(serializers.Serializer):
        token = serializers.CharField()
    

    然后我在前面的推导中添加了一个信号接收器 CustomPasswordResetView ,现在不再派生自 rest_auth.views.PasswordResetView 添加了新视图 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重置链接的选项,因此前端将向Django发送一个POST请求,如下所示:

    // 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 */ )
    

    创建的电子邮件将包含如下链接:

    Click the link below to reset your password.
    
    localhost:8000/password-reset/4873759c229f17a94546a63eb7c3d482e73983495fa40c7ec2a3d9ca1adcf017
    

    …在django URL中没有定义 用心! Django将允许所有未知的URL通过,Vue路由器将决定该URL是否有意义。 然后,我让前端发送令牌以查看它是否有效,这样用户就可以查看令牌是否已经被使用、过期或其他…

    // 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或密码输入字段收到一条错误消息,在这里他们可以最终重置密码,密码将由前端发送,如下所示:

    // 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 */ )
    

    这是主代码。我使用自定义Vue路由将django rest端点与前端可见路由分离。其余的处理通过API请求完成,并处理它们的响应。

    希望这能帮助将来像我这样有斗争的人。

        2
  •  0
  •   yofee    6 年前

    我们有相同的设置,我可以告诉你,它是有效的,但我不能帮助你的基础36,除了 Django documentation 说它是64基!

    然而,你已经写到,这个理论部分对你来说并不重要,让我们来找出你遗漏的要点。设置有点混乱,因为你不需要所有的阿拉斯。我不知道你究竟被困在哪里。因此,我想告诉你我是如何做到的:

    我为Django/Allauth定义了密码重置URL,以便在电子邮件中创建链接时找到它:

    from django.views.generic import TemplateView
    
    PASSWORD_RESET = (
        r'^auth/password-reset-confirmation/'
        r'(?P<uidb64>[0-9A-Za-z_\-]+)/'
        r'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$'
    )
    
    urlpatterns += [
        re_path(
            PASSWORD_RESET,
            TemplateView.as_view(),
            name='password_reset_confirm',
        ),
    ]
    

    你不必这么做(因为你 include('allauth.urls') 实际上你 don't need these URLs )但我想澄清的是,这个URL并没有指向后端!也就是说,让您的前端为这个URL提供一个表单来输入一个新密码,然后使用AXIOS或其他东西来 POST uid , token , new_password1 new_password2 到你的终点。

    在您的例子中,端点是

    path(
        'reset-password-confirm/',
        acc_views.CustomPasswordResetConfirmView.as_view(),
        name='reset-password-confirm'
    ),
    

    这对你有帮助吗?否则,请告诉我。