简体   繁体   English

如何判断用户的电子邮件地址是否已使用 Django、allauth、rest-auth 和自定义用户进行验证

[英]How to tell if user's email address has been verified using Django, allauth, rest-auth and a custom user

I'm using Django 2.0.10 with rest-framework, rest-auth and allauth.我正在使用带有 rest-framework、rest-auth 和 allauth 的 Django 2.0.10。 I have a custom user model.我有一个自定义用户模型。

I've got email verification working by using the allauth view.我已经使用 allauth 视图进行电子邮件验证。 The verification email is sent when a user registers.验证电子邮件在用户注册时发送。 If I click the link in the email, I'm taken to a page with a button to click to verify the email.如果我单击电子邮件中的链接,我会被带到一个页面,该页面带有一个按钮以单击以验证电子邮件。 This all works without error.这一切都没有错误。 However what I can't find out is what this actually does .但是我不知道这实际上是什么的。 No field in the user's data seems to change.用户数据中的任何字段似乎都没有改变。

The behaviour I want is for users to be able to register and login, but only to be able to add content to the site after they have verified their email.我想要的行为是让用户能够注册和登录,但只有在他们验证了他们的电子邮件后才能向网站添加内容。

Edit: this post gives part of the answer but doesn't say how to save the verification status as a property of the user so that you can check it in the front end when you load the user data.编辑: 这篇文章给出了部分答案,但没有说明如何将验证状态保存为用户的属性,以便在加载用户数据时可以在前端进行检查。

settings.py设置.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 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用户/模型.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

When a user logs in, how can I find out if they have verified their email address?当用户登录时,我怎样才能知道他们是否已经验证了他们的电子邮件地址? Thanks for any help!谢谢你的帮助!

Aha!啊哈! Thanks to this post and this post , I think I have an answer.感谢这篇文章这篇文章,我想我有了答案。

The email address's status is saved in a separate table EmailAdress, not as part of the User model.电子邮件地址的状态保存在单独的表 EmailAdress 中,而不是作为 User 模型的一部分。 This can be accessed in a modelviewset as follows:这可以在模型视图集中访问,如下所示:

api.py 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())

            ...

This will return True if the user has any verified email address.如果用户有任何经过验证的电子邮件地址,这将返回 True。

However, it's much more useful to add the verification status to the user.但是,将验证状态添加给用户会更有用。 This can be done with a signal as explained here .这可以通过此处解释的信号来完成。

views.py视图.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()

Now in api.py you can check like this:现在在 api.py 你可以像这样检查:

print(self.request.user.email_verified)

This works if you have a single email address that can't be changed or deleted.如果您有一个无法更改或删除的电子邮件地址,则此方法有效。 If you allow multiple email addresses I guess you'd need to make more checks and update the user's status accordingly.如果您允许多个电子邮件地址,我想您需要进行更多检查并相应地更新用户的状态。 But I have only a single email address which is used for login, so I think that's OK.但是我只有一个用于登录的电子邮件地址,所以我认为没关系。

I think it would be better practice to make 'email_verified' part of a user profile, but this is a working demo.我认为将“email_verified”作为用户配置文件的一部分是更好的做法,但这是一个有效的演示。

I had the same problem, I was able to solve this by using the code below:我有同样的问题,我可以通过使用下面的代码来解决这个问题:

#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

]

The code above allowed me to create new users with the registration url.上面的代码允许我使用注册 url 创建新用户。 After which are sent an email with a link.之后会发送一封带有链接的电子邮件。 When users click on the link they are redirected to the login page, with their email now verified in the database.当用户点击链接时,他们会被重定向到登录页面,他们的电子邮件现在已在数据库中验证。

Try SerializerMethodField尝试SerializerMethodField

The official example:官方例子:

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

There's a function for this.有一个功能。

Syntax:句法:

from allauth.account.utils import has_verified_email
has_verified_email(user, email=None) -> bool

According to the source code this does the same thing as what the accepted answer does when email is None .根据源代码,这与emailNone时接受的答案的作用相同。 Otherwise it checks if the user has that verified email.否则,它会检查用户是否拥有经过验证的电子邮件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM