我希望在Django中添加电子邮件帐户验证。我尝试使用django-registration应用程序来实现,但似乎它还没有更新为完全兼容自定义用户模型,这会导致太多问题。是否有其他可靠且文档完整的应用程序可以让我在Django中的用户注册时发送验证电子邮件?
我希望在Django中添加电子邮件帐户验证。我尝试使用django-registration应用程序来实现,但似乎它还没有更新为完全兼容自定义用户模型,这会导致太多问题。是否有其他可靠且文档完整的应用程序可以让我在Django中的用户注册时发送验证电子邮件?
我如何个人处理电子邮件注册:
首先,我的个人资料扩展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
文件中,Registration类: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()
send_mail
没有提供任何工具来验证您的电子邮件。如果您想要验证您的电子邮件(DKIM,SPF),我建议您查看这个链接:https://djangosnippets.org/snippets/1995/
NB3: 视图new_activation_link存在一个安全问题:它应该检查请求重新发送的用户是否正确,并且也应该检查该用户是否已经通过身份验证。请您对此进行修正。django.utils.crypto
中的get_random_string
(在使用startproject
时提供默认的“ SECRET_KEY”)或者如果使用Python3.6以上版本,则使用新的“secrets”模块。否则,请使用os.urandom
获取真正的随机数据,而不是random.random
。 - Bakuriureg_data['activation_url'] = request.build_absolute_uri('/activate/')
。这个答案是在2014年写的/2017年编辑的,但对我设置电子邮件确认非常有帮助!感谢@Raphael和@Bakuriu。 - TomVerifiedEmailField
: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')
user = super(UserCreationForm, self).save(commit=False)
之后,我应该设置user.is_active = False
,然后发送带有确认代码的电子邮件,而且没有任何插件,这可以简单地完成吗? - sdotslezek