Django第5章: auth补充之用户注册,密码找回

Posted fqh202

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django第5章: auth补充之用户注册,密码找回相关的知识,希望对你有一定的参考价值。

自定义以邮箱和密码登录用户

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模块

  1. 安装模块: pip install django-simple-captcha;
  2. 增加captchaINSTALLED_APPS中;
  3. 生成captcha表: manage.py migrate;
  4. 配置urls.py:

    urlpatterns += [
    url(r'^captcha/', include('captcha.urls')),
    ]
  5. 设置cpatchamodel

    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()
  6. 在模板直接导入 {{RegisterForm.captcha}} 即可显示对应的图片和输入框还有隐藏的框

  7. 验证码的错误这个模块会自行进行校验,无须自己手动写逻辑;

注册逻辑
// 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>邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱</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>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</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>验&nbsp;证&nbsp;码</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('发送成功')

激活用户

  1. 每发送一次邮件, 都会生成email_verify_record对象,包括email,codesend_type三个字段,保存在数据库;

  2. 配置url(r‘^activate/(\S{16})/‘, ActivateView.as_view(), name=‘activate‘),, 由对应的视图函数接收16位验证码;

  3. 激活逻辑

    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')

密码找回

  1. 若忘记密码.需要提交邮箱和验证码,进行发送邮件

    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})
  2. 用户收到激活地址后,进入重置密码页面,此时将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>
  3. 提交重置表单

    // 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})

以上是关于Django第5章: auth补充之用户注册,密码找回的主要内容,如果未能解决你的问题,请参考以下文章

Django之outh模块

Django第1章补充: Xadmin管理系统, 自定义user表

Django组件之auth

Django之用户认证Auth组件

Django 之 auth 模块

python之auth模块