【问题标题】:How to tell if user's email address has been verified using Django, allauth, rest-auth and a custom user如何判断用户的电子邮件地址是否已使用 Django、allauth、rest-auth 和自定义用户进行验证
【发布时间】:2019-06-25 07:29:05
【问题描述】:

我正在使用带有 rest-framework、rest-auth 和 allauth 的 Django 2.0.10。我有一个自定义用户模型。

我已使用 allauth 视图进行电子邮件验证。验证电子邮件在用户注册时发送。如果我单击电子邮件中的链接,我会被带到一个页面,该页面带有一个按钮以单击以验证电子邮件。这一切都没有错误。但是,我不知道这实际上是什么。用户数据中的任何字段似乎都没有变化。

我想要的行为是让用户能够注册和登录,但只有在他们验证了他们的电子邮件后才能向网站添加内容。

编辑:this post 给出了部分答案,但没有说明如何将验证状态保存为用户的属性,以便您在加载用户数据时可以在前端进行检查。

settings.py

# django rest auth
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
OLD_PASSWORD_FIELD_ENABLED = True
LOGOUT_ON_PASSWORD_CHANGE = False
ACCOUNT_EMAIL_VERIFICATION = 'optional'

api/urls.py

from allauth.account.views import confirm_email

urlpatterns = [
    re_path(r'^rest-auth/registration/account-confirm-email/(?P<key>[-:\w]+)/$', confirm_email,
     name='account_confirm_email'),
...
]

users/models.py

import uuid 

from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
from django.utils.http import int_to_base36

class CustomUserManager(UserManager):
    def get_by_natural_key(self, username):
        case_insensitive_username_field = '{}__iexact'.format(self.model.USERNAME_FIELD)
        return self.get(**{case_insensitive_username_field: username})

ID_LENGTH = 12

def pkgen():
    from base64 import b32encode
    from hashlib import sha1
    from random import random

    pk = int_to_base36(uuid.uuid4().int)[:ID_LENGTH]
    return pk

class CustomUser(AbstractUser):
    objects = CustomUserManager()
    slug = models.CharField(max_length=ID_LENGTH, default=pkgen, editable=False)
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    def __str__(self):
        return self.email

当用户登录时,我怎样才能知道他们是否已经验证了他们的电子邮件地址?感谢您的帮助!

【问题讨论】:

  • 最简单的解决方案是在注册时向用户发送电子邮件确认时将user.is_active 设置为False。并在他/她确认电子邮件时将user.is_active 设置为True。同样在没有确认电子邮件的注册用户尝试登录之前,您检查该用户是否有is_status..TrueFalse。如果是False,则不允许他们登录。
  • 谢谢,但我希望用户能够立即登录,而不是创建内容。一个原因是他们可以请求新的验证电子邮件,例如,如果它没有到达或者他们在垃圾邮件中丢失了它。
  • 然后你可以简单地在他们的个人资料中添加一个布尔类型的额外字段,即verified,然后根据他们是否确认电子邮件将其设置为TrueFalse。然后,您可以使用此信息来禁止他们编辑内容。
  • 你能解释一下我会怎么做吗?我很高兴更改我的代码,但我不想重写 allauth 代码。
  • 该帖子是我获得如何检查电子邮件地址状态的信息的地方,但它没有说明在验证电子邮件地址后如何更改用户对象?

标签: django django-allauth email-confirmation


【解决方案1】:

啊哈!感谢this postthis post,我想我有答案了。

电子邮件地址的状态保存在单独的表 EmailAdress 中,而不是作为用户模型的一部分。这可以在模型视图集中访问,如下所示:

api.py

from allauth.account.admin import EmailAddress

class ListViewSet(viewsets.ModelViewSet):
    ...

    def get_queryset(self):
        # can view public lists and lists the user created
        if self.request.user.is_authenticated:
            print('is there a verified email address?')
            print(EmailAddress.objects.filter(user=self.request.user, verified=True).exists())

            ...

如果用户有任何经过验证的电子邮件地址,这将返回 True。

但是,将验证状态添加给用户会更有用。这可以通过here 解释的信号来完成。

views.py

from allauth.account.signals import email_confirmed
from django.dispatch import receiver

@receiver(email_confirmed)
def email_confirmed_(request, email_address, **kwargs):
    user = email_address.user
    user.email_verified = True

    user.save()

现在在 api.py 你可以像这样检查:

print(self.request.user.email_verified)

如果您有一个无法更改或删除的电子邮件地址,则此方法有效。如果您允许多个电子邮件地址,我想您需要进行更多检查并相应地更新用户的状态。但是我只有一个用于登录的电子邮件地址,所以我认为没关系。

我认为将“email_verified”作为用户配置文件的一部分会更好,但这是一个有效的演示。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我可以使用下面的代码解决这个问题:

    #Project-level folder urls.py
    from django.contrib import admin
    from django.urls import path, include
    from allauth.account.views import ConfirmEmailView, EmailVerificationSentView 
    #These ConfirmEmailView, EmailVerificationSentView are very important
    #I used other allauth/ dj-rest-auth views and they didn't automatically verify the email.
    
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('dj-rest-auth/registration/account-confirm-email/<str:key>/',
        ConfirmEmailView.as_view()), #This is at the top because apparently won't work if below. #Integral to problem solution
    
    path('dj-rest-auth/', include('dj_rest_auth.urls')),
    path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
    path('api-auth', include('rest_framework.urls')),
    
     path('dj-rest-auth/registration/account-confirm-email/', 
      EmailVerificationSentView.as_view(),
            name='account_email_verification_sent'),#Integral to problem solution
    
    ]
    

    上面的代码允许我使用注册 url 创建新用户。之后会发送一封带有链接的电子邮件。当用户点击链接时,他们将被重定向到登录页面,他们的电子邮件现在已在数据库中验证。

    【讨论】:

      【解决方案3】:

      试试SerializerMethodField

      官方例子:

      from django.contrib.auth.models import User
      from django.utils.timezone import now
      from rest_framework import serializers
      
      class UserSerializer(serializers.ModelSerializer):
          days_since_joined = serializers.SerializerMethodField()
      
          class Meta:
              model = User
              fields = '__all__'
      
          def get_days_since_joined(self, obj):
              return (now() - obj.date_joined).days
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-22
        • 2020-02-28
        • 2014-09-16
        • 1970-01-01
        • 2020-02-21
        • 2016-02-09
        • 2020-03-18
        相关资源
        最近更新 更多