自定义以邮箱和密码登录用户
1. 重载authenticate()
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from userinfo.models import UserProfile
class CustomBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
# 以username或者email字段匹配用户输入的usernma内容
user = UserProfile.objects.filter(Q(username=username)|Q(email=username)).first()
# 匹配出用户记录后再进一步匹配密码
if user.check_password(password):
# 返回用户
return user
else:
return None
2. 修改配置文件
AUTHENTICATION_BACKENDS = (
'userinfo.views.CustomBackend',
)
外部验证码模块应用
django-simple-captcha模块
- 安装模块:
pip install django-simple-captcha
; - 增加
captcha
到INSTALLED_APPS
中; - 生成captcha表:
manage.py migrate
; 配置
urls.py
:urlpatterns += [ url(r'^captcha/', include('captcha.urls')), ]
设置
cpatcha
的model
from captcha.fields import CaptchaField from django import forms class RegisterForm(forms.Form): username = forms.CharField(max_length=12, min_length=2, required=True) password = forms.CharField(min_length=4, required=True) captcha = CaptchaField()
在模板直接导入
{{RegisterForm.captcha}}
即可显示对应的图片和输入框还有隐藏的框验证码的错误这个模块会自行进行校验,无须自己手动写逻辑;
注册逻辑
// views.py
class RegisterView(View):
def get(self, request):
register_form = RegisterForm()
return render(request, 'register.html', {
'register_form': register_form,
})
def post(self, request):
register_form = RegisterForm(request.POST)
if register_form.is_valid():
email = register_form.cleaned_data.get('email', '')
// 过滤重复注册
if UserProfile.objects.filter(email=email):
return render(request, 'register.html', {'msg':'用户已注册', 'register_form':register_form})
else:
password = register_form.cleaned_data.get('password', '')
# 新建用户
new_user = UserProfile()
new_user.username = email
new_user.email = email
# 非常重要, 用户没有激活链接前必须为False
new_user.is_active = False
# 对密码进行加密处理,利用django自带的加密方法
new_user.password = make_password(password)
new_user.save()
# 发送邮件进行激活验证
send_email(email, 'register')
return render(request, 'send_email_success.html')
else:
# form自行检测字段不合格
return render(request, 'register.html', {'register_form': register_form})
// register.html
<form method="post" action="{% url 'register' %}" autocomplete="off">
<!--若用户名form表单出现错误信息,则加上errorput属性-->
<div class="form-group marb20 {% if register_form.errors.email %}errorput{% endif %}">
<label>邮 箱</label>
<input type="text" id="id_email" name="email" value="" placeholder="请输入您的邮箱地址" autocomplete="On" />
</div>
<!--同上-->
<div class="form-group marb8 {% if register_form.errors.password %}errorput{% endif %}">
<label>密 码</label>
<input type="password" id="id_password" name="password" value="" placeholder="请输入6-20位非中文字符密码" />
</div>
<div class="form-group marb8 captcha1 {% if register_form.errors.captcha %}errorput{% endif %}">
<label>验 证 码</label>
{{ register_form.captcha }}
</div>
<!-- 循环列出表单的报错信息 -->
<div class="error btns" id="jsEmailTips"> {{ msg }} {% for key, value in register_form.errors.items %} {{ key }}{{ value }} {% endfor %}</div>
<div class="auto-box marb8">
</div>
<input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
{% csrf_token %}
</form>
发送邮件
setting文件配置
EMAIL_HOST = "smtp.qq.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'qgmlmnhulqupbdij'
EMAIL_USE_TLS = True
EMAIL_FROM = EMAIL_HOST_USER
发送邮件逻辑
# send_email.py
// 由激活视图函数通过验证后才调用此函数
from datetime import datetime
import random, string
from django.core.mail import send_mail # django自带的邮件发送模块
from onlineLearningSys.settings import EMAIL_FROM
from userinfo.models import EmailVerifyRecord
def generate_random_str(num):
# 生成特定位数的字符串
return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(num))
def send_email(email, send_type = ''):
if type == "change_email":
code = generate_random_str(4)
else:
code = generate_random_str(16)
# 实例化邮件激活码对象,并在数据库生成记录
email_verify_record = EmailVerifyRecord()
email_verify_record.email = email
email_verify_record.code = code
email_verify_record.send_type = send_type
email_verify_record.send_time = datetime.now()
email_verify_record.save()
email_title = ""
email_body = ""
if send_type == 'register':
email_title = 'MXonline在线网注册激活连接'
email_body = '请点击下面的链接重置密码: http://127.0.0.1:8000/user/activate/{0}'.format(code)
# 固定格式书写
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
print('发送成功')
elif send_type == 'forget':
email_title = 'MXonline在线网密码重置连接'
// 当用户点击此网址时候,会触发对应的视图函数,并且接收到对应的值;
email_body = '请点击下面的链接激活的你的账号: http://127.0.0.1:8000/user/reset/{0}'.format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
print('发送成功')
elif send_type == 'change_email':
email_title = 'MXonline在线网绑定邮箱更改链接'
email_body = '请复制您的验证码 : {0}'.format(code)
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
print('发送成功')
激活用户
每发送一次邮件, 都会生成
email_verify_record
对象,包括email
,code
和send_type
三个字段,保存在数据库;配置
url(r‘^activate/(\S{16})/‘, ActivateView.as_view(), name=‘activate‘),
, 由对应的视图函数接收16位验证码;激活逻辑
class ActivateView(View): def get(self, request, code): email_record = EmailVerifyRecord.objects.filter(code=code) # 根据传过来的code在数据库中取出相应的邮件激活记录 if email_record: record = email_record.first() email = record.email user = UserProfile.objects.get(email=email) user.is_active = True print('激活成功') user.save() return redirect('/user/login/') else: return render(request, 'register.html')
密码找回
若忘记密码.需要提交邮箱和验证码,进行发送邮件
class ForgetPwd(View): # 忘记密码 def get(self, request): forget_p_form = ForgetPwdForm() return render(request, 'forgetpwd.html', {'forget_p_form': forget_p_form}) def post(self, request): forget_p_form = ForgetPwdForm(request.POST) if forget_p_form.is_valid(): email = forget_p_form.cleaned_data.get("email", '') # 根据邮箱信息进行用户过滤 user = UserProfile.objects.filter(Q(username=email)|Q(email=email)) if user: send_email(email, 'forget') return render(request, 'send_email_success.html') else: # 用户不存在 return render(request, 'forgetpwd.html', {'forget_p_form': forget_p_form, 'msg': '对不起,该邮箱未被注册'}) else: return render(request, 'forgetpwd.html', {'forget_p_form': forget_p_form})
用户收到激活地址后,进入重置密码页面,此时将email渲染如模板中
# 第一次访问时候先将用户的email的值渲染进模板里保存起来 urlpatterns = [url(r'^reset/(\S{16})/', ResetPwd.as_view()),] # 此处必须单独写一个get函数,仅限于用户第一次点击激活地址进入 class ResetPwd(View): def get(self, request, code): # 进入密码重置界面 # 获取邮箱验证记录 email_record = EmailVerifyRecord.objects.filter(code=code) if email_record: record = email_record.first() email = record.email # 通过注册邮箱找到用户 user = UserProfile.objects.filter(email=email) if user: # 存在相关用户,跳转至登录页面 return render(request, 'password_reset.html', {"email":email}) // html <form id="reset_password_form" action="{% url 'reset-pwd' %}" method="post"> <ul> <li> <span class="">新 密 码 :</span> <input type="password" name="password_1" id="pwd" placeholder="6-20位非中文字符"> <i>{{ pwd_reset_form.errors.password_1 }}</i> </li> <input name="email" type="hidden" value="{{ email }}"> <li> <span class="">确定密码:</span> <input type="password" name="password_2" id="repwd" placeholder="6-20位非中文字符"> <i>{{ pwd_reset_form.errors.password_1 }}</i> <i>{{ msg }}</i> </li> <li class="button"> <input type="submit" value="提交" onclick="reset_password_form_submit()"> </li> </ul> {% csrf_token %} </form>
提交重置表单
// urls.py urlpatterns = [url(r'^reset/', ResetPwdView.as_view(), name='reset-pwd'), ] // views.py class ResetPwdView(View): def post(self, request): pwd_reset_form = PwdResetForm(request.POST) email = request.POST.get('email', '') if pwd_reset_form.is_valid(): password_1 = pwd_reset_form.cleaned_data.get('password_1') password_2 = pwd_reset_form.cleaned_data.get('password_2') if password_1 == password_2: user = UserProfile.objects.filter(Q(email=email)|Q(username=email)) if user: user = user.first() user.password = make_password(password_1) user.save() print('密码修改成功') return render(request, 'login.html') else: # 用户不存在 return render(request, 'password_reset.html', {'msg':'用户不存在'}) else: return render(request, 'password_reset.html', {'msg': '密码输入不一致', 'pwd_reset_form':pwd_reset_form, 'email':email}) else: return render(request, 'password_reset.html', {'pwd_reset_form':pwd_reset_form, 'email':email})