Django 自定义用户电子邮件帐户验证

     2023-02-24     85

关键词:

【中文标题】Django 自定义用户电子邮件帐户验证【英文标题】:Django Custom User Email Account Verification 【发布时间】:2014-09-16 02:24:50 【问题描述】:

我希望在 Django 中添加电子邮件帐户验证。我曾尝试使用 django-registration 应用程序来执行此操作,但它似乎没有更新为与自定义用户模型完全兼容,这会导致太多问题。是否有另一个可靠且有据可查的应用程序允许我在 django 中发送有关用户注册的验证电子邮件?

【问题讨论】:

您如何实际处理新用户的注册?是自定义表格吗?如果是这样,您可以覆盖 save 方法来发送您的电子邮件(将用户创建为非活动用户,生成一个您将在电子邮件中发送的链接,当转到此链接时,激活用户) 是的,我正在使用自定义 UserCreationForm 来创建用户。那么在那个保存方法中,在user = super(UserCreationForm, self).save(commit=False)之后,我应该设置user.is_active = False,然后发送一封带有确认码的电子邮件,并且没有任何插件可以简单地完成吗? 【参考方案1】:

我如何亲自处理电子邮件注册:

首先,我的个人资料扩展了 Django 用户 (models.py):

class Profile(models.Model):
    user = models.OneToOneField(User, related_name='profile') #1 to 1 link with Django User
    activation_key = models.CharField(max_length=40)
    key_expires = models.DateTimeField()

forms.py,注册类:

class RegistrationForm(forms.Form):
    username = forms.CharField(label="",widget=forms.TextInput(attrs='placeholder': 'Nom d\'utilisateur','class':'form-control input-perso'),max_length=30,min_length=3,validators=[isValidUsername, validators.validate_slug])
    email = forms.EmailField(label="",widget=forms.EmailInput(attrs='placeholder': 'Email','class':'form-control input-perso'),max_length=100,error_messages='invalid': ("Email invalide."),validators=[isValidEmail])
    password1 = forms.CharField(label="",max_length=50,min_length=6,
                                widget=forms.PasswordInput(attrs='placeholder': 'Mot de passe','class':'form-control input-perso'))
    password2 = forms.CharField(label="",max_length=50,min_length=6,
                                widget=forms.PasswordInput(attrs='placeholder': 'Confirmer mot de passe','class':'form-control input-perso'))

    #recaptcha = ReCaptchaField()

    #Override clean method to check password match
    def clean(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password1 != password2:
            self._errors['password2'] = ErrorList([u"Le mot de passe ne correspond pas."])

        return self.cleaned_data

    #Override of save method for saving both User and Profile objects
    def save(self, datas):
        u = User.objects.create_user(datas['username'],
                                     datas['email'],
                                     datas['password1'])
        u.is_active = False
        u.save()
        profile=Profile()
        profile.user=u
        profile.activation_key=datas['activation_key']
        profile.key_expires=datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=2), "%Y-%m-%d %H:%M:%S")
        profile.save()
        return u

    #Sending activation email ------>>>!! Warning : Domain name is hardcoded below !!<<<------
    #The email is written in a text file (it contains templatetags which are populated by the method below)
    def sendEmail(self, datas):
        link="http://yourdomain.com/activate/"+datas['activation_key']
        c=Context('activation_link':link,'username':datas['username'])
        f = open(MEDIA_ROOT+datas['email_path'], 'r')
        t = Template(f.read())
        f.close()
        message=t.render(c)
        #print unicode(message).encode('utf8')
        send_mail(datas['email_subject'], message, 'yourdomain <no-reply@yourdomain.com>', [datas['email']], fail_silently=False)

现在,在views.py,我们需要处理所有这些,让我们开始吧:

寄存器视图:

def register(request):
    if request.user.is_authenticated():
        return redirect(home)
    registration_form = RegistrationForm()
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            datas=
            datas['username']=form.cleaned_data['username']
            datas['email']=form.cleaned_data['email']
            datas['password1']=form.cleaned_data['password1']

            #We generate a random activation key
            salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
            usernamesalt = datas['username']
            if isinstance(usernamesalt, unicode):
                usernamesalt = usernamesalt.encode('utf8')
            datas['activation_key']= hashlib.sha1(salt+usernamesalt).hexdigest()

            datas['email_path']="/ActivationEmail.txt"
            datas['email_subject']="Activation de votre compte yourdomain"

            form.sendEmail(datas)
            form.save(datas) #Save the user and his profile

            request.session['registered']=True #For display purposes
            return redirect(home)
        else:
            registration_form = form #Display form with error messages (incorrect fields, etc)
    return render(request, 'siteApp/register.html', locals())

激活视图:

#View called from activation email. Activate user if link didn't expire (48h default), or offer to
#send a second link if the first expired.
def activation(request, key):
    activation_expired = False
    already_active = False
    profile = get_object_or_404(Profile, activation_key=key)
    if profile.user.is_active == False:
        if timezone.now() > profile.key_expires:
            activation_expired = True #Display: offer the user to send a new activation link
            id_user = profile.user.id
        else: #Activation successful
            profile.user.is_active = True
            profile.user.save()

    #If user is already active, simply display error message
    else:
        already_active = True #Display : error message
    return render(request, 'siteApp/activation.html', locals())

def new_activation_link(request, user_id):
    form = RegistrationForm()
    datas=
    user = User.objects.get(id=user_id)
    if user is not None and not user.is_active:
        datas['username']=user.username
        datas['email']=user.email
        datas['email_path']="/ResendEmail.txt"
        datas['email_subject']="Nouveau lien d'activation yourdomain"

        salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
        usernamesalt = datas['username']
        if isinstance(usernamesalt, unicode):
            usernamesalt = usernamesalt.encode('utf8')
        datas['activation_key']= hashlib.sha1(salt+usernamesalt).hexdigest()

        profile = Profile.objects.get(user=user)
        profile.activation_key = datas['activation_key']
        profile.key_expires = datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=2), "%Y-%m-%d %H:%M:%S")
        profile.save()

        form.sendEmail(datas)
        request.session['new_link']=True #Display: new link sent

    return redirect(home)

最后,在urls.py

url(r'^register/$', 'register'),
url(r'^activate/(?P<key>.+)$', 'activation'),
url(r'^new-activation-link/(?P<user_id>\d+)/$', 'new_activation_link'),

有了所有你应该开始的东西,在 .txt 电子邮件和 HTML 中使用适当的模板标签,它应该可以工作。

注意:这段代码并不完美,存在重复(例如,随机密钥的生成可以在函数中定义),但它完成了工作。另外:激活密钥不是使用适当的加密函数生成的。另一种方法是使用如下函数来生成密钥:

from django.utils.crypto import get_random_string

def generate_activation_key(username):
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
    secret_key = get_random_string(20, chars)
    return hashlib.sha256((secret_key + username).encode('utf-8')).hexdigest()

NB2:Django send_mail 不提供任何工具来验证您的电子邮件。如果你想验证你的电子邮件(DKIM、SPF),我建议你看看这个:https://djangosnippets.org/snippets/1995/

NB3:new_activation_link 视图存在安全问题:它应该检查请求重新发送的用户是否正确,以及他是否尚未通过身份验证。我让你改正。

【讨论】:

@Raphael Laurent 那么,“登录”应该如何使用令牌完成?上面的答案是“保存()”而不是登录 警告: 这个答案没有使用安全的方式来生成激活密钥,而是仅依赖于 random 模块。获取安全值的一种简单方法是使用django.utils.crypto 中的get_random_string(这用于在使用startproject 时提供默认的SECRET_KEY),或者,如果使用python3.6>,则使用新的secrets 模块.否则使用os.urandom而不是random.random获取真实随机数据。 @raphael-laurent 我可以使用 uuid4() 生成随机密钥吗? 如果您想避免在电子邮件中对激活链接进行硬编码,可以在 views.py 中执行 reg_data['activation_url'] = request.build_absolute_uri('/activate/')。这个答案写于 2014 年/编辑于 2017 年,但对我设置电子邮件确认仍然非常有帮助!谢谢@Raphael 和@Bakuriu。【参考方案2】:

您可能还对简单但功能强大的django-verified-email-field 感兴趣。

只需在您的表单中使用VerifiedEmailField

from django import forms
from verified_email_field.forms import VerifiedEmailField

class RegistrationForm(forms.ModelForm):
    email = VerifiedEmailField(label='email', required=True)

或在您的模型中:

from django.db import models
from verified_email_field.models import VerifiedEmailField

class User(models.Model):
    email = VerifiedEmailField('e-mail')

它呈现两个输入字段:e-mailverification code。验证码使用 AJAX 或在字段的 clean 期间发送到电子邮件地址,如果给定电子邮件没有有效代码,因此即使没有 javascript 也可以工作。

【讨论】:

你能简单解释一下吗..请 我已经简单解释过了。我不确定我应该更深入地解释哪一部分,除非你问一些特别的问题。 这是一个非常糟糕的文档库 它不是一个库,只是一个(虽然功能强大)模型/表单字段。 (当您购买锤子时您期望什么文档?我想重量和木材种类就足够了。)如果您错过任何重要的文档,欢迎您扩展文档。或者您可以提出一些合理的问题,我会回答并可能更新自述文件。

Django Rest Framework 自定义身份验证 + 返回自定义 json

...验证对用户进行身份验证,并在验证用户后返回令牌以及电子邮件和id。settinge.pyAUTHENT 查看详情

从 django 用户模型迁移到自定义用户模型

...个参考(one和two)来拥有一个自定义用户模型,以便通过电子邮件进行身份验证,并为其添加一个额外的字段。classUser(AbstractBaseUser,PermissionsMixin):email=mo 查看详情

Django 创建自定义 UserCreationForm

...只要求输入用户名和两个密码/密码确认字段。我还想要电子邮件和全名字段,都设置为必填字段。我已经这样做了:fromdjango.contrib.au 查看详情

Django 创建自定义 UserCreationForm

...只要求输入用户名和两个密码/密码确认字段。我还想要电子邮件和全名字段,都设置为必填字段。我已经这样做了:fromdjango.contrib.au 查看详情

在 Django 中使用自定义用户模型总是在模板中返回匿名用户

...:我创建了一个自定义用户模型,因为我需要三个信息(电子邮件、机构ID、密码)来登录系统。为此,我还创建了一个身份验证后端。当我尝试登录时,它会重定向到正确的视图。但模板显示匿名用 查看详情

根据 Woocommerce 中的用户角色自定义客户新帐户邮件

...和专业的。我想要的是根据注册时选择的角色发送不同的电子邮件。以下代码允许新用户在注册时立 查看详情

django 完成邮件验证

...前,我想解决一些问题。我想确保用户有一个名为email的电子邮件字段。他们还有一个is_verified字段来指示电子邮件是否已经过验证。大多数电子邮件验证实施都存在一些缺陷。假设用户创建了一个帐户并拥有未经验证的电子邮... 查看详情

如何自定义 django rest auth 密码重置电子邮件内容/模板

】如何自定义djangorestauth密码重置电子邮件内容/模板【英文标题】:Howtocustomizedjangorestauthpasswordresetemailcontent/template【发布时间】:2016-04-2604:02:41【问题描述】:在djangorest_auth密码重置中,默认电子邮件内容如下所示:-您收到这... 查看详情

在 Django 1.5 自定义用户模型中使用电子邮件作为用户名字段导致 FieldError

】在Django1.5自定义用户模型中使用电子邮件作为用户名字段导致FieldError【英文标题】:UsingemailasusernamefieldinDjango1.5customUsermodelresultsinFieldError【发布时间】:2013-03-1321:27:47【问题描述】:我想使用电子邮件字段作为自定义用户模... 查看详情

Django,自定义身份验证登录。身份验证失败时如何显示错误消息?

...建一个自定义身份验证登录。一切似乎都在工作,除了在电子邮件和密码不正确时显示错误消息。我知道这与我在登录失败时渲染login 查看详情

django自定义用户视图?

...500:01:29【问题描述】:我进行自定义用户。所以我需要用电子邮件登录。user=authenticate(email=email,password=password)似乎不起作用...帮我...让我知道如何修复我的views.py。这是我的看法。fromdjango.contrib.auth.decora 查看详情

自定义 Firebase 电子邮件模板 [重复]

】自定义Firebase电子邮件模板[重复]【英文标题】:CustomizeFirebaseemailtemplate[duplicate]【发布时间】:2018-10-0622:25:25【问题描述】:当用户使用firebase创建帐户时,我使用firebaseUser.sendVerficiationEmail()向用户发送验证链接。它完美地工... 查看详情

django之用户认证auth组件(代码片段)

...(User)存储用户信息,包括用户名、密码和电子邮件地址。通过配置,可以使用扩展的用户模型(例如添加额外的自定义字段)。视图:Django的认证组件包含了一系列视图,用于处理用户认证(... 查看详情

为后端的每个用户创建 Django User 对象

...:59【问题描述】:我正在编写一个自定义后端,用于通过电子邮件地址而不是用户名对用户进行身份验证。我已经编写了一个继承自AbstractUser的自定义User模型:classUser(AbstractUser):email=models.Emai 查看详情

使用注册表单添加到自定义用户字段(django)

...些问题。目前用户可以注册并保存他们的用户名、密码、电子邮件、名字和姓氏,但所有其他表单数据都没有保存到对象中。以下是我的 查看详情

无法使用用户名/密码登录令牌端点:drf 令牌身份验证和自定义用户模型,Django

...密码登录令牌端点:drf令牌身份验证和自定义用户模型,Django【英文标题】:Cannotlogintotokenendpointwithusername/password:drftokenauthandcustomusermodel,Django【发布时间】:2022-01-2213:22:14【问题描述】:我有一个使用Djangorest框架的基本Django应... 查看详情

Django - 更新用户/帐户管理

...我的用户帐户信息。我有一个ok表单,它只显示一个密码/电子邮件字段并清理电子邮件字段。我的观点有问题。这是我得到的错误:无法通过用户实例访问管理器。这是我的观点:my_account函数。defmy_account(request):u 查看详情

django-allauth:如何仅在电子邮件验证后将用户设置为活动状态

】django-allauth:如何仅在电子邮件验证后将用户设置为活动状态【英文标题】:django-allauth:Howtosetusertoactiveonlyaftere-mailverification【发布时间】:2014-09-0714:11:09【问题描述】:我主要将django-allauth用作为管理后端创建用户帐户的一种... 查看详情