Django---用户登陆注册系统的实现(二)

1 图片验证码

(1)在Django中,django-simple-captcha库包提供了图形验证码的使用。

pip install django-simple-captcha

(2)在settings.py文件中注册captcha:loginRegister/settings.py

在这里插入图片描述
(3)执行数据迁移,在数据表中生成captcha_captchastore表

python manage.py migrate

在这里插入图片描述

(4)添加路由:loginRegister/urls.py
在这里插入图片描述
(5)创建表单模型:login/forms.py

from  django import forms
from  captcha.fields import  CaptchaField
class LoginForm(forms.Form):
    username=forms.CharField(label='用户名',required=True,min_length=4,max_length=128)
    password=forms.CharField(label='密码',required=True,min_length=4,max_length=128)
    captcha=CaptchaField(label='验证码')

(6)视图逻辑优化:login/views.py

def login(request):
    # 请求方法为POST提交
    if request.method == 'POST':
    #  实例化表单对象
        login_form=LoginForm(request.POST)
        # 验证表单数据的合法性              
        if login_form.is_valid():
        # 获取表单填写的数据,数据清洗
            username = request.POST.get('username').strip()
            password = request.POST.get('password').strip()
            user = SiteUser.objects.filter(name=username, password=password).first()
            if user:
                request.session['is_login']=True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                return redirect('/index/')
            else:
                message = "用户名或者密码错误"
                #  locals()以字典方式返回当前所有的变量
                return render(request, 'login/login.html', locals())
        else:
            message = "非法的信息"
            return render(request, 'login/login.html', locals())
    ## 请求方法是GET请求
    login_form=LoginForm()
    return render(request, 'login/login.html',locals())

(7)Template页面优化:templates/login/login.html

<div class="col-sm">
            <h3 style="text-align: center">用户登录</h3>
            # 不同的报错,提示不同的信息
             {% if login_form.captcha.errors %}
                <div class="alert alert-warning" role="alert">
                    <strong>登录失败!</strong> 验证码不正确
                </div>
            {% elif message %}
                <div class="alert alert-warning" role="alert">
                    <strong>登录失败!</strong> {{ message }}
                </div>
            {% endif %}

            <form action="/login/" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label>{{ login_form.username.label }}</label>
                    <input type="text" class="form-control" name="username">
                </div>
                <div class="form-group">
                ## 返回login_form.password.label的信息
                    <label>{{ login_form.password.label }}</label>
                    <input type="password" class="form-control" name="password">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                #添加验证码表单
                <div class="form-group">
                    <label>{{ login_form.captcha.label }}</label>
                    {{ login_form.captcha }}
                </div>
                <a href="/register/" class="text-success">
                    <ins>新用户注册</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">登录</button>
            </form>

        </div>

(8)测试

  • 输入账号或密码不正确

在这里插入图片描述

  • 输入账号密码正确,验证码错误时

在这里插入图片描述

  • 账号密码及验证码正确,成功登录

在这里插入图片描述

2 邮箱注册

2.1 发送邮件功能

(1)获取授权码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)配置邮件信息
在这里插入图片描述
(3)交互式环境中测试发送邮件:

python manage.py shell
from django.core.mail import send_mail
from loginRegister.settings import EMAIL_HOST_USER
send_mail("测试邮件", "content", EMAIL_HOST_USER, ['收件邮箱地址'])

在这里插入图片描述
在这里插入图片描述

2.2 基本的注册功能实现

(1)注册表单:login/forms.py

class RegisterForm(forms.Form):
    username=forms.CharField(label='用户名',required=True,max_length=128)
    password1=forms.CharField(label='密码',required=True,max_length=128)
    password2 = forms.CharField(label='密码', required=True, max_length=128)
    email = forms.EmailField(label="邮箱地址")
    captcha=CaptchaField(label='验证码')

(2)实现注册视图:login/views.py

如果用户已经登录,则不能注册跳转到首页。
如果是GET请求,返回用户注册的html页面。
如果是POST请求, 先验证提交的数据是否通过,清洗数据。 接下来判断用户名和邮箱是否已经被
注册, 将注册的信息存储到数据库,跳转到登录界面。
额外功能: 为了数据的安全性注册时,密码存储到数据库不是明文存储,而是先加密再存储。
def register(request):
    # 如果用户已经登录,则不能注册跳转到首页。
    if request.session.get('is_login', None):
        return redirect('/index/')
    # 如果是POST请求
    if request.method == 'POST':
        print(request.POST)
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        # 先验证提交的数据是否通过
        if register_form.is_valid():
            # 清洗数据
            username = register_form.cleaned_data.get('username')
            password1 = register_form.cleaned_data.get('password1')
            password2 = register_form.cleaned_data.get('password2')
            email = register_form.cleaned_data.get('email')

            print(locals())
            # 接下来判断用户名和邮箱是否已经被注册
            same_name_user = SiteUser.objects.filter(name=username)
            print(same_name_user)
            if same_name_user:
                message = '用户名已经存在'
                return render(request, 'login/register.html', locals())
            same_email_user = SiteUser.objects.filter(email=email)
            if same_email_user:
                message = '该邮箱已经被注册了!'
                return render(request, 'login/register.html', locals())
            # 将注册的信息存储到数据库,跳转到登录界面
            new_user = SiteUser(name=username, password=password1, email=email)
            new_user.save()
            return  redirect('/login/')
    # 如果是GET请求,返回用户注册的html页面。
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())

(3)注册的html界面:templates/login/register.html

<div class="col-sm">
            <h3 style="text-align: center">用户注册</h3>
            {% if register_form.captcha.errors %}
                <div class="alert alert-warning" role="alert">
                    <strong>注册失败!</strong> 验证码不正确
                </div>
            {% elif message %}
                <div class="alert alert-warning" role="alert">
                    <strong>注册失败!</strong> {{ message }}
                </div>
            {% endif %}
            <form action="/register/" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label>{{ register_form.username.label }}</label>
                    <input type="text" class="form-control" name="username">
                </div>
                <div class="form-group">
                    <label>{{ register_form.email.label }}</label>
                    <input type="email" class="form-control" name="email">
                </div>
                <div class="form-group">
                    <label>{{ register_form.password1.label }}</label>
                    <input type="password" class="form-control" name="password1">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>{{ register_form.password2.label }}</label>
                    <input type="password" class="form-control" name="password2">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>{{ register_form.captcha.label }}</label>
                    {{ register_form.captcha }}
                </div>
                <a href="/login/" class="text-success">
                    <ins>用户登录</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">注册</button>
            </form>

        </div>

2.3 注册添加密码加密功能

(1)使用Python内置的hashlib库:login/utils.py

import hashlib

def hash_code(s, salt='mysite'):# 加点盐
    h = hashlib.sha256()
    s += salt
    h.update(s.encode())  # update方法只接收bytes类型
    return h.hexdigest()

(2)修改login和register视图:login/views.py
在这里插入图片描述

在这里插入图片描述

2.4 邮件注册确认

用邮件确认的方式对新注册用户进行审查,既安全又正式,也是目前很多站点的做法。

(1)创建模型:login/models.py

  • 既然要区分通过和未通过邮件确认的用户,那么必须给用户添加一个是否进行过邮件确认的属性。需要创建一张新表,用于保存用户的确认码以及注册提交的时间
class SiteUser(models.Model):
    has_confirmed = models.BooleanField(default=False, verbose_name="是否邮箱验 证")
class ConfirmString(models.Model):
    code = models.CharField(max_length=256, verbose_name="确认码")
    user = models.OneToOneField('SiteUser', on_delete=models.CASCADE)
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    def __str__(self):
        return self.user.name + ":" + self.code

    class Meta:
        ordering = ["-create_time"]
        verbose_name = "确认码"
        verbose_name_plural = "确认码"

(2)数据库模型更改,一定要生成迁移脚本和写入数据库

python manage.py makemigrations
python manage.py migrate

(3)修改一下admin.py文件,方便在后台修改和观察数据

在这里插入图片描述

(4)修改视图:login/views.py

def register(request):
    # 如果用户已经登录,则不能注册跳转到首页。
    if request.session.get('is_login', None):
        return redirect('/index/')
    # 如果是POST请求
    if request.method == 'POST':
        print(request.POST)
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        # 先验证提交的数据是否通过
        if register_form.is_valid():
            # 清洗数据
            username = register_form.cleaned_data.get('username')
            password1 = register_form.cleaned_data.get('password1')
            password2 = register_form.cleaned_data.get('password2')
            email = register_form.cleaned_data.get('email')

            print(locals())
            # 接下来判断用户名和邮箱是否已经被注册
            same_name_user = SiteUser.objects.filter(name=username)
            print(same_name_user)
            if same_name_user:
                message = '用户名已经存在'
                return render(request, 'login/register.html', locals())
            same_email_user = SiteUser.objects.filter(email=email)
            if same_email_user:
                message = '该邮箱已经被注册了!'
                return render(request, 'login/register.html', locals())
            # 将注册的信息存储到数据库,跳转到登录界面
            try:
                # 将注册的信息存储到数据库,跳转到登录界面
                new_user = SiteUser(name=username, password=hash_code(password1), email=email)
                new_user.save()
                # 生成确认码并发送确认邮件
                code = make_confirm_string(new_user)
                print('code:', code)
                send_email(email, code)
                message = '请前往邮箱进行确认!'
            except Exception:
                new_user.delete()
                message = '发送邮件失败!'
                return render(request, 'login/register.html', locals())
            else:
                return redirect('/login/')
    # 如果是GET请求,返回用户注册的html页面。
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())

(5)login/utils.py

import datetime
## make_confirm_string() 是创建确认码对象的方法
def make_confirm_string(user):
    """生成确认码"""
    print("生成确认码.....")
    # 获取当前时间
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    code = hash_code(user.name, now)
    print('in code:',code)
    ConfirmString.objects.create(code=code, user=user)
    return code

## send_email(email, code) 方法接收两个参数,分别是注册的邮箱和前面生成的哈希值
def send_email(email, code):
    print('send mail.........')
    subject = '注册确认邮件'
    text_content = '''感谢注册,这里是登录注册系统网站!\
                    如果你看到这条消息,说明你的邮箱服务器不提供HTML链接功能,请联系管理员!'''
    html_content = '''
    <p>感谢注册<a href="http://{}/confirm/?code={}" target=blank>点击验证</a>,\
    这里是登录注册系统网站!</p>
    <p>请点击站点链接完成注册确认!</p>
    <p>此链接有效期为{}天!</p>
    '''.format('127.0.0.1:9999', code, settings.CONFIRM_DAYS)

    send_mail(subject, text_content,
              settings.EMAIL_HOST_USER, [email, ], html_message=html_content)
  • 有效期天数为设置在settings.py
 CONFIRM_DAYS=3

(6)测试:
在这里插入图片描述

2.5 处理邮件确认请求

(1)在login子应用的 urls.py 中添加一条url
在这里插入图片描述
(2)在 login/views.py 中添加一个 user_confirm 视图

  • 获取确认码信息:数据库中是否有该确认码,如果没有, 返回说是无效的请求;数据库中是否有该确认码,如果有, 判断是否过期?
    如果过期,删除用户信息,否则更新用户信息。
def user_confirm(request):
    code = request.GET.get('code', None)
    message = ''
    try:
        confirm = ConfirmString.objects.get(code=code)
    except:
        message = '无效的确认请求!'
        return render(request, 'login/confirm.html', locals())

    create_time = confirm.create_time
    now = datetime.now()
    print(now, create_time, create_time + timedelta(settings.CONFIRM_DAYS))
    if now > create_time + timedelta(settings.CONFIRM_DAYS):
        confirm.user.delete()
        message = '您的邮件已经过期!请重新注册!'
    else:
        confirm.user.has_confirmed = True
        confirm.user.save()
        confirm.delete()
        message = '感谢确认,请使用账户登录!'
    return render(request, 'login/confirm.html', locals())

(3)新建 login/templates/login/confirm.html文件:

  • 页面中通过JS代码,设置2秒后自动跳转到登录页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="margin-left: 100px;">{{ message }}</h1>

<script>
window.setTimeout("window.location='/login/'",2000);
</script>

</body>
</html>

(4)修改登录规则:login/views.py

  • 未进行邮件确认的用户不能登录如下所示:

在这里插入图片描述
(5)测试

  • 注册后未邮件确认的用户不能登陆

在这里插入图片描述

在这里插入图片描述

  • 邮件确认跳转的页面

在这里插入图片描述

  • 用户成功登陆

在这里插入图片描述

在这里插入图片描述

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值