验证码图片生成
图片背景随机生成
验证码图片每次登录的时候都会刷新不同的验证码,有两种方式:
- 本地存储所有验证码图片,每次返回本地验证码图片,很占资源,不建议使用
- 后台自动生成验证码图片,每次返回随机生成的图片
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>blog</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<script src="/static/js/bootstrap.min.js"></script>
</head>
<body>
<h1>登录</h1>
<div class="row">
<div class="col-md-6 col-lh-offset-3">
<form>
<div class="form-group">
<label for="user">用户名</label>
<input type="text" id="user" 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">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="txt" class="valid_code form-control">
</div>
<div class="col-md-6">
<img width="270" height="40" id="valid_code_img" src="/get_validCode_img">
</div>
</div>
</div>
</form>
</div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script>
// 刷新验证码
$('#valid_code_img').click(function (){
$(this)[0].src+="?"
})
</script>
</body>
</html>
# views.py
def get_validCode_img(request):
def get_random_color():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
# 方式一
# with open('dog.jpg') as f:
# data = f.read()
# 方式二 pillow 模块
# 使用磁盘作为存储,每次都需要写入文件打开文件,IO磁盘操作都是很慢的
# from PIL import Image
# img = Image.new('RGB', (270, 40), (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
#
# with open('validCode.png', 'wb') as f:
# img.save(f, 'png')
#
# with open('validCode.png', 'rb') as f:
# data = f.read()
# 方式3 使用内存句柄,不经过磁盘
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
img = Image.new('RGB', (270, 40), get_random_color())
# 在图片上增加文字
draw = ImageDraw.Draw(img)
halfings_font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)
# 随机字符生成
for i in range(5):
random_number = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_upper_alpha = chr(random.randint(65,90))
random_char = random.choice([random_low_alpha, random_number, random_upper_alpha])
draw.text((i*50+20, 5), random_char, get_random_color(), font=halfings_font)
# 噪点噪线
width = 270
height = 40
# 划线
for i in range(5):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=get_random_color())
# 画点
for i in range(30):
draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
f = BytesIO()
img.save(f, 'png')
data = f.getvalue()
return HttpResponse(data)
知识点
PIL 模块使用
BytesIO 模块使用
效果展示
验证码校验
思路:在生成验证码图片的时候,需将生成的校验码保存到session中,保证每个用户之间的校验码是单独的,互不影响。在校验用户输入的时候将其从session中拿出来校验即可。
登录点击使用ajax来完成,对数据校验之后出现的错误数据进行局部显示,用来提示用户。
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>blog</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<script src="/static/js/bootstrap.min.js"></script>
</head>
<body>
<h1>登录</h1>
<div class="row">
<div class="col-md-6 col-lh-offset-3">
<form>
{% csrf_token %}
<div class="form-group">
<label for="user">用户名</label>
<input type="text" id="user" 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">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="txt" class="form-control" id="valid_code">
</div>
<div class="col-md-6">
<img width="270" height="40" id="valid_code_img" src="/get_validCode_img">
</div>
</div>
</div>
<div class="form-group">
<input type="button" class="btn btn-default login_btn pull-right" value="登录">
</div>
</form>
</div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script>
// 刷新验证码
$('#valid_code_img').click(function (){
$(this)[0].src+="?"
})
// 校验验证码
$('.login_btn').click(function () {
$.ajax({
url:"",
type:"post",
data:{
'user':$('#user').val(),
'pwd':$('#pwd').val(),
'valid_code':$('#valid_code').val(),
'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()
},
success:function(data){
console.log(data)
}
})
})
</script>
</body>
</html>
后端代码
def login(request):
if request.method == "POST":
response = {'user': None, 'msg': None}
user = request.POST.get('user')
pwd = request.POST.get('pwd')
valid_code = request.POST.get('valid_code')
# 校验验证码输入
valid_code_str = request.session.get('valid_code_str')
if valid_code.lower() == valid_code_str.lower():
# 用户名密码校验
pass
else:
response['msg'] = 'valid code error'
print(user, pwd, valid_code)
return JsonResponse(response)
return render(request, 'login.html')
def get_validCode_img(request):
def get_random_color():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
# 方式3 使用内存句柄,不经过磁盘
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
img = Image.new('RGB', (270, 40), get_random_color())
# 在图片上增加文字
draw = ImageDraw.Draw(img)
halfings_font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)
# 保存生成的随机验证码
valid_code_str = ''
# 随机字符生成
for i in range(5):
random_number = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_upper_alpha = chr(random.randint(65,90))
random_char = random.choice([random_low_alpha, random_number, random_upper_alpha])
draw.text((i*50+20, 5), random_char, get_random_color(), font=halfings_font)
valid_code_str += random_char
# 存储生成验证码到session中,保证每一个人的都是独立的
request.session['valid_code_str'] = valid_code_str
# 噪点噪线
width = 270
height = 40
# 划线
for i in range(5):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=get_random_color())
# 画点
for i in range(30):
draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
f = BytesIO()
img.save(f, 'png')
data = f.getvalue()
return HttpResponse(data)
用到的知识点
request.session
request.session[''key] = value 存储数据到session中
request.session.get('key') 获取session中的数据
ajax
css结合ajax增加点击事件:
<input type="button" class="btn btn-default login_btn pull-right" value="登录">
$('.login_btn').click(function () {}
ajax成功函数中的log显示:
console.log(data)
ajax获取name为某固定值的标签的value内容
$("[name='csrfmiddlewaretoken']").val()
前端效果展示
登录校验
使用auth模块做用户认证功能,当用户认证成功后,需对当前用户进行注册,request.user就等于了当前登录用户,并且全局可以用。
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>blog</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<script src="/static/js/bootstrap.min.js"></script>
</head>
<body>
<h1>登录</h1>
<div class="row">
<div class="col-md-6 col-lh-offset-3">
<form>
{% csrf_token %}
<div class="form-group">
<label for="user">用户名</label>
<input type="text" id="user" 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">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="txt" class="form-control" id="valid_code">
</div>
<div class="col-md-6">
<img width="270" height="40" id="valid_code_img" src="/get_validCode_img">
</div>
</div>
</div>
<div class="form-group">
<input type="button" class="btn btn-default login_btn" value="登录">
<span id="error_info"></span>
</div>
</form>
</div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script>
// 刷新验证码
$('#valid_code_img').click(function (){
$(this)[0].src+="?"
})
// 校验验证码
$('.login_btn').click(function () {
$.ajax({
url:"",
type:"post",
data:{
'user':$('#user').val(),
'pwd':$('#pwd').val(),
'valid_code':$('#valid_code').val(),
'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()
},
success:function(data){
console.log(data)
if (data.user){
// 用户成功登录之后的跳转
location.href = "/index"
}
else {
// 显示错误信息,text修改标签之间的内容,css增加css样式
$('#error_info').text(data.msg).css({"color":"red", "margin-left":"20px"})
// 定时任务,多久之后执行对应函数。对错误信息显示后自动消失
setTimeout(function (){
$('#error_info').text("")
}, 1000)
}
}
}
})
})
</script>
</body>
</html>
后端代码:
def login(request):
if request.method == "POST":
response = {'user': None, 'msg': None}
user = request.POST.get('user')
pwd = request.POST.get('pwd')
valid_code = request.POST.get('valid_code')
# 校验验证码输入
valid_code_str = request.session.get('valid_code_str')
if valid_code.lower() == valid_code_str.lower():
# 用户名密码校验
login_user = auth.authenticate(username=user, password=pwd)
if login_user:
# 用户校验成功,进行注册,request.user== 当前登录对象,丙炔全局可用
auth.login(request, login_user)
response['user'] = login_user.username
else:
response['msg'] = 'username or password error'
else:
response['msg'] = 'valid code error'
print(user, pwd, valid_code)
return JsonResponse(response)
return render(request, 'login.html')
用到的知识点
auth模块的使用
ajax对标签内容的替换和前端跳转
ajax定时多久执行函数