目录
一、路由设计
from django.conf.urls import url from django.contrib import admin from bbs import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), # 用于login前端页面对于验证码的获取 url(r'^get_valid_code/', views.get_valid_code), url(r'^index/', views.index), url(r'^register/', views.register), ]
二、 前端设计
注意知识点:
- {% csrf_token %}
- 验证码img用路由获取:<img id="img_code" height="35" width="320" src="/get_valid_code/" alt="">
- js实现点击验证码范围实现页面刷新
{# 实现点击验证码进行页面刷新:获取当前路径添加内容实现刷新(例如添加‘?’)#} $('#img_code').click(function () { $('#img_code')[0].src += '?' });
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/jquery-3.3.1.js"></script> <title>登录</title> </head> <style> .has-error { color: red; } </style> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>登录</h1> {# label for="name" 如果指定某个id,这样点击这个label,焦点会到对应的控件上 #} <form> {% csrf_token %} <div class="form-group"> <label for="name">用户名</label> <input type="text" id="name" class="form-control"> </div> <div class="form-group"> <label for="pwd">密码</label> <input type="password" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="valid_code">验证码</label> <div class="row"> <div class="col-md-6"> <input type="text" id="valid_code" class="form-control"> </div> <img id="img_code" height="35" width="320" src="/get_valid_code/" alt=""> </div> </div> <span class="has-error"></span> <input type="button" id='btn' value="登录" class="btn btn-primary pull-right"> </form> </div> </div> </div> </body> <script> {# 实现点击验证码进行页面刷新:获取当前路径添加内容实现刷新(例如添加‘?’)#} $('#img_code').click(function () { $('#img_code')[0].src += '?' }); {# 实现ajax传输数据给后台#} $('#btn').click(function () { $('#img_code')[0].src += '?'; $.ajax({ url: '/login/', type: 'post', data: { 'name': $('#name').val(), 'pwd': $('#pwd').val(), 'valid_code': $('#valid_code').val(), 'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val(), }, success: function (data) { if (data.user) { // 默认跳转index页面,若存在前一个网页跳转则返回前一个网页 location.href = data.next } else { $('.has-error').html(data.msg) } } }) }) </script> </html>
三、view视图函数设计
from django.shortcuts import render, HttpResponse from PIL import Image, ImageDraw, ImageFont import random from io import BytesIO from django.contrib import auth from django.http import JsonResponse # ----------- 登陆 ------------------- def login(request): ''' 登陆验证 - 使用auth进行登陆验证 auth.authenticate - 使用auth对验证通过的用户进行登陆 auth.login - 验证码通过获取request内的sessionid进行比对验证,忽略大小写 :param request: :return: ''' if request.method == 'GET': return render(request, 'login.html') elif request.is_ajax(): response = {'user': None, 'msg': None, 'next': '/index/'} name = request.POST.get('name') pwd = request.POST.get('pwd') valid_code = request.POST.get('valid_code') # 使用upper方法来忽视大小写区别 if valid_code.upper() == request.session.get('valid_code').upper(): user = auth.authenticate(request, username=name, password=pwd) if user: auth.login(request, user) response['user'] = name response['msg'] = '登陆成功' # 配合auth组件的 @login_required(login_url='/login/')使用,前端进行跳转 next_url = request.GET.get('next') if next_url: response['next'] = next_url else: response['msg'] = '用户名密码错误' else: response['msg'] = '验证码错误' return JsonResponse(response) def get_random_color(): ''' 获取随机颜色,返回(0,0,0)元组 -仿rgb(0,0,0) :return: ''' return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),) def get_valid_code(request): ''' 获取随机验证码(pillow模板+random模块+IO模块) - 使用随机背景色 - 随机字符串(数字,大小写) - 存在干扰项(线、点、弧) - 将随机字符串进行存储(放在session中) :param request: :return: ''' img = Image.new('RGB', (320, 35), color=get_random_color()) # 创建对象,歘惹怒图像成为画布 img_draw = ImageDraw.Draw(img) # 生成一个字体对象,参数1:字体样式文件的路径,参数2::字体大小 '''注意!若win库里没有对应字体写API时会报错,确认对应在C:/Windows/Fonts下,或者文件包中存在''' font = ImageFont.truetype('static/font/ss.TTF', size=25) random_code = '' # 自动生成验证码内文字,数字,大写字母,小写字母 for i in range(5): num = str(random.randint(0, 9)) c_upper = chr(random.randint(65, 90)) c_lower = chr(random.randint(97, 122)) s = random.choice([num, c_upper, c_lower]) random_code += s # 自动生成验证码坐标,相对坐标 - 第一个从0开始 p = (i * 30 + 50, i) # 参数1:xy的坐标,参数2:要写的文字,参数3:写文字的颜色,参数4:字体 # 每次循环渲染一个 img_draw.text(p, s, get_random_color(), font=font) # 将上述随机字符串保存在session中,用于登陆验证 request.session['valid_code'] = random_code print(random_code) # 设置验证框的长宽,作为干扰项的画图范围 height = 35 weight = 320 # 在验证码上添加干扰线 for i in range(10): y = random.randint(0, height) y2 = random.randint(0, height) x = random.randint(0, weight) x2 = random.randint(0, weight) # 设置画线的起始和结束,填充颜色 img_draw.line((x, x2, y, y2), fill=get_random_color()) # 在验证码上添加干扰点 和 干扰狐仙 -- 不建议与上方干扰线一起放置 存在重叠 for i in range(100): y = random.randint(0, height) x = random.randint(0, weight) img_draw.point([x, y], fill=get_random_color()) img_draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color()) # from io import BytesIO # BytesIO() 以二进制形式存储在内存中 # 放到内存中,存取比较快,而且有自动清理 # 将文件以二进制的形式,以png格式保存在内存中 f = BytesIO() img.save(f, 'png') data = f.getvalue() return HttpResponse(data)