python

Django用户登录的实现及随机验证码功能

2018-06-28  本文已影响189人  吾星喵

Django用户登录的实现及随机验证码功能

使用自带的登录视图

登录URL

from django.contrib.auth.views import login, logout

urlpatterns = [
    url(r'^login/$', login, name='login'),
    url(r'^logout/$', logout, name='logout'),
]

settings中创建登录链接

LOGIN_REDIRECT_URL = reverse_lazy('event:list')
LOGIN_URL = reverse_lazy('login')
LOGOUT_URL = reverse_lazy('logout')

自定义登录模板

在应用的templates目录下,创建registration文件夹,然后创建login.html文件,将优先使用这个模板进行登录

<div class="card">
    <div class="card-body login-card-body">
        <p class="login-box-msg">登录</p>

        <form action="{% url 'account:login' %}" method="post">
            <div class="form-group has-feedback">
                <input type="text" name="username" class="form-control" placeholder="用户名/邮箱" value="{% if form.username.value %}{{ form.username.value }}{% endif %}">
                <span class="fa fa-envelope form-control-feedback">{{ form.username.errors }}</span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" name="password" class="form-control" placeholder="密码">
                <span class="fa fa-lock form-control-feedback">{{ form.password.errors }}</span>
            </div>
            <div class="row">
                <div class="col-8">
                </div>
                <div class="col-4">
                    <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
                </div>
            </div>
            <input type="hidden" name="next" value="{{ next }}" />
            {% csrf_token %}
        </form>

        <p class="mb-1">
            <a href="#">忘记密码</a>
        </p>
        <p class="mb-0">
            <a href="#" class="text-center">注册用户</a>
        </p>
    </div>
    <!-- /.login-card-body -->
</div>

自定义登录视图进行验证登录

image.png image.png

创建登录视图my_login(request)

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User


# 自定义登录视图
def my_login(request):
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        verify = request.POST.get('verify', '')
        verify_session = request.session.get('verify', '')
        next_url = request.GET.get('next')
        # print('session中的验证码', verify_session)
        # print('输入的验证码:', verify)
        if verify.lower() == verify_session.lower():
            if User.objects.filter(username=username):
                login_user = authenticate(username=username, password=password)
                if login_user:
                    login(request, login_user)
                    if next_url and next_url.strip() != '':
                        # 如果下一跳地址不空,且不为空字符串,则登录成功跳回登录前的页面
                        return redirect(next_url)
                    else:
                        # 登录成功,跳转到主页
                        return redirect(reverse('index'))
                else:
                    msg_password = '密码错误,请检查'
            else:
                msg_username = '账户不存在,请重新注册'
        else:
            msg_verify = '验证码错误,请重新输入'

    next_url = request.GET.get('next', '')  # 访问登录,首先获取next的值,如果没有,则next_url赋值为''
    return render(request, 'registration/login.html', locals())

验证码视图verify_image(request, width, height)

# 返回验证码图片
def verify_image(request, width, height):
    words_count = 4  # 验证码中的字符长度
    width = int(width)  # 图片宽度
    height = int(height)  # 图片高度
    size = int(min(width / words_count, height) / 1.3)  # 字体大小设置
    bg_color = (randint(200, 255), randint(200, 255), randint(200, 255))   # 随机背景色(浅色)
    img = Image.new('RGB', (width, height), bg_color)  # 创建图像
    # 第一个参数是颜色通道,这里使用了RGB通道,还有其他的一些通道,如CMYK之类的,但不用管
    # 第二个参数是由宽高组成的元组,数字
    # 第三个参数是图片的背景色,这里用rgb的颜色显示,例如( 255, 255, 255),注意这是元组

    font = ImageFont.truetype('arial.ttf', size)  # 导入字体
    # 用到了ImageFont的truetype函数,可以自动查询电脑中的字体
    # 第一个参数是字体名字
    # 第二个参数是字体大小
    # 注意这个是windows系统下默认的字体,其他系统自己找

    draw = ImageDraw.Draw(img)  # # 创建画笔
    # 用到了ImageDraw的Draw函数
    # 有且只有一个参数,就是之前创建的画布

    # text = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    text = string.digits + string.ascii_letters  # 数字+大写字母
    verify_text = ''
    for i in range(words_count):
        text_color = (randint(0, 160), randint(0, 160), randint(0, 160))  # 确定文字的颜色,要随机的颜色,颜色要比较深
        left = width * i / words_count + (width / 4 - size) / 2  # i为第几个文字
        top = (height - size) / 2

        word = text[randint(0, len(text) - 1)]
        verify_text += word
        draw.text((left, top), word, font=font, fill=text_color)
        # 写字需要使用draw的text方法
        # 第一个参数是一个坐标轴元组,分别是距离左边和上边的距离
        # 第二个参数是要写的字(字符串)
        # 后面的两个参数分别是字体和字体颜色

    for i in range(30):
        text_color = (255, 255, 255)  # 颜色:白色
        left = randint(0, width)  # 位置:随机
        top = randint(0, height)
        draw.text((left, top), '*', font=font, fill=text_color)

    for i in range(5):
        line_color = (randint(0, 160), randint(0, 160), randint(0, 160))  # 颜色:随机
        line = (randint(0, width), randint(0, height), randint(0, width), randint(0, height))  # 位置:头尾都随机
        draw.line(line, fill=line_color)
        # 画线条需要使用draw的line方法
        # 第一个参数是包含了两个坐标的元组,分别是线条一头一尾的坐标
        # 后面的参数是线条的颜色

    del draw

    # StringIO,可以将图片缓存到内存里面,读取后就清空内存
    image_stream = BytesIO()  # 建立一个缓存对象
    # print(image_stream)  # 类似于:<_io.BytesIO object at 0x0000022CE22C00F8>
    img.save(image_stream, 'jpeg')  # 将图片保存到内存中
    # print(img, image_stream.getvalue())
    request.session['verify'] = verify_text  # 保存相应的文字在session里面
    return HttpResponse(image_stream.getvalue(), 'image/jpeg')  # 返回内存中的图片

修改登录URL

from .views import my_login


urlpatterns = [
    # url(r'^login/$', login, name='login'),
    url(r'^login/$', my_login, name='login'),
    url(r'^logout/$', logout, name='logout'),
    url(r'^verify_image/(\d+)/(\d+)/$', verify_image, name='verify_image')  # http://127.0.0.1:8000/account/verify_image/200/80/
]

自定义登录模板

{% extends "base_account.html" %}

{% block title %}登录{% endblock %}

{% block content %}
<div class="card">
    <div class="card-body login-card-body">
        <p class="login-box-msg">登录</p>

        <form action="{% url 'account:login' %}?next={{ next_url }}" method="post">
            <div class="form-group has-feedback">
                <input type="text" name="username" class="form-control" placeholder="用户名/邮箱" value="{% if form.username.value %}{{ form.username.value }}{% endif %}{{ username }}">
                <span class="fa fa-user form-control-feedback"><small class="text-warning">&nbsp;&nbsp;{{ form.username.errors }}{{ msg_username }}</small></span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" name="password" class="form-control" placeholder="密码">
                <span class="fa fa-lock form-control-feedback"><small class="text-warning">&nbsp;&nbsp;{{ form.password.errors }}{{ msg_password }}</small></span>
            </div>
            <div class="form-group has-feedback">
                <div class="row">
                    <div class="col-8">
                        <input type="text" name="verify" class="form-control" placeholder="验证码">
                    </div>
                    <div class="col-4">
                        <span class="form-control-feedback" title="点击切换验证码" id="id_change_verify" onclick="change_verify()"><img src="{% url 'account:verify_image' 100 36 %}" /></span>
                    </div>
                </div>
                <span class="fa fa-picture-o form-control-feedback"><small class="text-warning">&nbsp;&nbsp;{{ msg_verify }}</small></span>
            </div>

            <div class="row">
                <div class="col-8">
                </div>
                <div class="col-4">
                    <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
                </div>
            </div>
            <input type="hidden" name="next" value="{{ next }}" />
            {% csrf_token %}
        </form>

        <p class="mb-1">
            <a href="#">忘记密码</a>
        </p>
        <p class="mb-0">
            <a href="#" class="text-center">注册用户</a>
        </p>
    </div>
    <!-- /.login-card-body -->
</div>


<script>
    function change_verify() {
        // alert('切换验证码');
        let url = "{% url 'account:verify_image' 100 36 %}";
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);  //get请求,请求地址,是否异步
        xhr.responseType = "blob";

        // 如果是跨域请求,需要用到下面两行代码,具体也不知道怎么用
        xhr.setRequestHeader("client_type", "DESKTOP_WEB");
        xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key="");

        xhr.onload = function() {
            if (this.status === 200) {
                let blob = this.response;
                // 二进制数据拿到了,那么要把它放在一个 html标签中,并且应该是img标签
                let img = document.createElement("img");
                img.onload = function(e) {
                    window.URL.revokeObjectURL(img.src);
                };
                //有问题,将blob直接加载到img中,由于blob太大,会有性能影响,上方函数就是释放
                img.src = window.URL.createObjectURL(blob);
                // alert(img);
                $("#id_change_verify").html(img);
            }
        };
        xhr.send();
    }
</script>

{% endblock %}

上一篇 下一篇

猜你喜欢

热点阅读