验证码
图形验证码
图形验证码逻辑分析
-
· 新建应用Verifications
- 将图形验证码的文字信息保存到 Redis数据库,为短信验证码做准备。
- UUID用于区分该图形验证码属于哪个用户,也可使用其他唯一标识信息来实现。
图形验证码接口设计
请求方式
选项 | 方案 |
---|---|
请求方法 | GET |
请求地址 | image_codes/(?P<uuid>[\w-]+)/ |
请求参数:路径参数
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
uuid | string | 是 | 唯一编号 |
响应结果
图形验证码接口定义
图形验证码视图
class ImageCodeView(View):
'''图像验证码'''
def get(self,request,uuid):
'''
:param uuid: 用于表示该图形验证码属于哪个用户
:return: image/jpg
'''
return HttpResponse('image/jpg')
图形验证码后端逻辑
准备captcha拓展包
captcha拓展包用于后端生成图形 验证码
链接: https://pan.baidu.com/s/1q5F1rrMcTaMd_ap1SXPWDw 提取码: gyes
准备Redis数据库
"verify_code":{#验证码
"BACKEND":"django_redis.cache.RedisCache",
"LOCATION":"redis://127.0.0.1:6379/2",
"OPTIONS":{
"CLIENT_CALSS":"django_redis.client.DefaultClient",
}
}
图片验证码后端逻辑实现
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
from verifications.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
class ImageCodeView(View):
'''图像验证码'''
def get(self,request,uuid):
'''
:param uuid: 用于表示该图形验证码属于哪个用户
:return: image/jpg
'''
#生成验证码,保存到redis,影响图形验证码
text,image=captcha.generate_captcha()
redis_conn = get_redis_connection('verify_code')
# redis_conn.set('img_%s'%uuid,text)
redis_conn.setex('img_%s'%uuid,300,text)
# return HttpResponse('image/jpg')
return HttpResponse(image,content_type='image/jpg')
class GetImageCodeView(View):
def get(self, request, uuid):
redis_coon = get_redis_connection('verify_code')
code_text = redis_coon.get('img_%s' % uuid)
print(code_text)
if code_text == None :
return JsonResponse({'code': 1, "errmsg": '验证码失效,请刷新验证码'})
else:
code_text=bytes.decode(code_text)
return JsonResponse({'code': 0, "errmsg": 'ok', "code_text": code_text})
urls.py
urlpatterns = [
re_path('image_codes/(?P<uuid>[\w-]+)/', views.ImageCodeView.as_view()),
re_path('image_code_text/(?P<uuid>[\w-]+)/', views.GetImageCodeView.as_view()),
]
图片验证码前端逻辑实现
Vue实现图形验证码展示
register.js
mounted(){
this.generate_image_code();
},
methods:{
//check_username:function(){
//},
generate_image_code(){
this.uuid=generateUUID()
this.image_code_url = '/image_codes/'+this.uuid+"/"
this.image_code_text_url='/image_code_text/'+this.uuid+"/"
},
}
register.html
<li>
<label>图形验证码:</label>
<input type="text" name="image_code" id="pic_code" class="msg_input">
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
<span class="error_tip">请填写图形验证码</span>
</li>
Vue实现图形验证码校验
register.html
<li>
<label>图形验证码:</label>
<input type="text" name="image_code" id="pic_code" class="msg_input">
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code" v-model="image_code" @blur="check_image_code">
<span class="error_tip" v-show="error_image_code">[[ error_image_code_message ]]</span>
</li>
register.js
check_image_code(){
axios.get(this.image_code_text_url,{responseType:"json"})
.then(response=>{
if(response.data.code ==0){
if(response.data.code_text != this.image_code.toUpperCase()){
this.error_image_code_message="验证码错误"
this.error_image_code=true
this.generate_image_code();
}else{
this.error_image_code=false}
}else{
this.error_image_code_message=response.data.errmsg
this.error_image_code=true
}})
.catch(error=>{
console.log(error.response)})
},
完整的文件内容
views.py
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse,JsonResponse
from verifications.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
class ImageCodeView(View):
'''图像验证码'''
def get(self,request,uuid):
'''
:param uuid: 用于表示该图形验证码属于哪个用户
:return: image/jpg
'''
#生成验证码,保存到redis,影响图形验证码
text,image=captcha.generate_captcha()
redis_conn = get_redis_connection('verify_code')
# redis_conn.set('img_%s'%uuid,text)
redis_conn.setex('img_%s'%uuid,30,text)
# return HttpResponse('image/jpg')
return HttpResponse(image,content_type='image/jpg')
class GetImageCodeView(View):
def get(self, request, uuid):
redis_coon = get_redis_connection('verify_code')
code_text = redis_coon.get('img_%s' % uuid)
print(code_text)
if code_text == None :
return JsonResponse({'code': 1, "errmsg": '验证码失效,请刷新验证码'})
else:
code_text=bytes.decode(code_text)
return JsonResponse({'code': 0, "errmsg": 'ok', "code_text": code_text})
register.js
//es6
let vm = new Vue({
el: "#app",
//修改vue读取变量的语法
delimiters:['[[',']]'],
data:{
// v-model
username:"",
password:"",
password2:"",
mobile:"",
allow:"",
image_code_url:'',
image_code_text_url:'',
uuid:'',
image_code:'',
//v-show
error_name:false,
error_password:false,
error_password2:false,
error_mobile:false,
error_allow:false,
error_image_code:false,
// error_message
error_name_message:"",
error_mobile_message:"",
error_image_code_message:"",
},
//页面加载完成后会被调用的方法
mounted(){
this.generate_image_code();
},
methods:{
//check_username:function(){
//},
generate_image_code(){
this.uuid=generateUUID()
this.image_code_url = '/image_codes/'+this.uuid+"/"
this.image_code_text_url='/image_code_text/'+this.uuid+"/"
},
check_username(){
let re = /^[a-aA-XZ0-9_-]{5,20}$/;
if(re.test(this.username)){
//匹配成功不展示
this.error_name=false
}else{
this.error_name =true
this.error_name_message= '请输入5-20个字符的用户名'
}
if(this.error_name == false){
let url='/users/usernames/'+this.username+'/count/'
axios.get(url,{
responseType:'json'
})
//请求成功的处理
.then(response=>{
if (response.data.count == 1){
//
this.error_name_message='用户名已经存在'
this.error_name=true
}else{
this.error_name=false
}
})
//请求失败的处理
.catch(error=>{
console.log(error.response)
})
}
},
check_password(){
let re = /^[a-aA-XZ0-9_-]{8,20}$/;
if(re.test(this.password)){
//匹配成功不展示
this.error_password=false
}else{
this.error_password = true
}
},
check_password2(){
if(this.password != this.password2){
this.error_password2 = true
}else{
this.error_password2 = false
}
},
check_mobile(){
let re = /^1[3456789]\d{9}$/;
if (re.test(this.mobile)){
this.error_mobile = false
}else{
this.error_mobile = true
this.error_mobile_message = "请输入正确的手机号码"
}
if(this.error_name == false){
let url='/users/mobiles/'+this.mobile+'/count/'
axios.get(url,{
responseType:'json'
})
//请求成功的处理
.then(response=>{
if (response.data.count == 1){
//
this.error_mobile_message='手机号已经存在'
this.error_mobile=true
}else{
this.error_mobile=false
}
})
//请求失败的处理
.catch(error=>{
console.log(error.response)
})
}
},
check_allow(){
if(!this.allow){
this.error_allow = true
}else{
this.error_allow = false
}
},
check_image_code(){
axios.get(this.image_code_text_url,{responseType:"json"})
.then(response=>{
if(response.data.code ==0){
if(response.data.code_text != this.image_code.toUpperCase()){
this.error_image_code_message="验证码错误"
this.error_image_code=true
this.generate_image_code();
}else{
this.error_image_code=false}
}else{
this.error_image_code_message=response.data.errmsg
this.error_image_code=true
}})
.catch(error=>{
console.log(error.response)})
},
on_submit(){//表单提交
if(this.error_name == true || this.error_password || this.error_password2 || this.error_mobile == true || this.error_allow == true || this.error_image_code == true|| this.username == "" || this.password == "" || this.password2 == "" || this.mobile == "" || this.allow == false){
//禁止表单提交
window.event.returnValue=false
}
},
}
})