allauth 未验证的电子邮件在电子邮件过期后仍未验证

allauth unverified email remains unverified once email expires

我有一个自定义用户模型。我使用 Django rest auth 来处理用户身份验证。 问题 是在发送电子邮件时注册后。如果用户在电子邮件过期之前没有验证电子邮件,它似乎会无限期地卡住。自从 ACCOUNT_EMAIL_VERIFICATION = "mandatory" 在我的设置中,我期待再次发送验证电子邮件,根据文档,它应该默认重新发送验证消息,但这并没有发生。我不知道还能做什么,而且我似乎找不到任何有帮助的资源。

下面是我的模型

models.py

class User(AbstractBaseUser, PermissionsMixin):
    username = None
    email = models.EmailField(max_length=254, unique=True)
    name = models.CharField(max_length=250)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    slug = models.SlugField(max_length=255, unique=True, blank=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']

在我的 settings.py 中,用户的有效期为 2 天

ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = True
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_CONFIRM_EMAIL_ON_GET = True
ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None #or "api/authenticated/"
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
ACCOUNT_EMAIL_CONFIRMATION_HMAC = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
EMAIL_VERIFICATION = "mandatory"
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"
ACCOUNT_EMAIL_CONFIRMATION_COOLDOWN = 3600
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 180
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = False
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
ACCOUNT_LOGIN_ON_PASSWORD_RESET = False
ACCOUNT_LOGOUT_REDIRECT_URL = "api/login/"
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = False
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USER_MODEL_EMAIL_FIELD = "email"

首先,您提到您正在使用 django-rest-auth,但事实并非如此,您可能正在使用 django-allauth

根据 django-allauth 的文档:

ACCOUNT_EMAIL_VERIFICATION:

When set to “mandatory” the user is blocked from logging in until the email address is verified. Choose “optional” or “none” to allow logins with an unverified e-mail address. In case of “optional”, the e-mail verification mail is still sent, whereas in case of “none” no e-mail verification mails are sent.

所以没有提到如果第一个过期重新发送验证邮件。要完成您想要的,您应该有一个 job 脚本 运行 并检查 expired 验证令牌并手动重新发送验证电子邮件。

您应该创建一个如下所示的脚本:

from time import sleep
from django.utils import timezone
from django_allauth.account.models import EmailConfirmation

while True:
    def_expired = timezone.now() - datetime.timedelta(days=app_settings.EMAIL_CONFIRMATION_EXPIRE_DAYS)
    expired_tokens = EmailConfirmation.objects.filter(sent__lte=def_expired)
    for token in expired_tokens:
        token.send()
    sleep(2)

并使用您喜欢的任何调度程序(supervisorpm2cronjob 等)保留此脚本 运行。

最重要的是,django-allauth not/can 没有您想要的功能。这项工作需要手动完成。

最终,我能够以不同的方式解决这个问题,我创建了一个视图并 URL 请求用户电子邮件,然后如果他们未经验证则向他们发送 link。

views.py

from allauth.account.utils import send_email_confirmation
from allauth.account.admin import EmailAddress
from rest_framework.exceptions import APIException


class EmailConfirmation(APIView):
    permission_classes = [AllowAny] 

    def post(self, request):
        user = get_object_or_404(User, email=request.data['email'])
        emailAddress = EmailAddress.objects.filter(user=user, verified=True).exists()

        if emailAddress:
            return Response({'message': 'This email is already verified'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            try:
                send_email_confirmation(request, user=user)
                return Response({'message': 'Email confirmation sent'}, status=status.HTTP_201_CREATED)
            except APIException:
                return Response({'message': 'This email does not exist, please create a new account'}, status=status.HTTP_403_FORBIDDEN)

urls.py

path('verify-email/again/', qv.EmailConfirmation.as_view(), name='resend-email-confirmation'),