一.背景

  在之前实现过django的图片验证码,有自己实现过的,也有基于django-simple-captcha的,都是基于form表单验证,若自己实现,可以获取相应的标签name便可以获取判断,若使用django-simple-captcha只需相应配置即可。但在前后端分离的情况下,就有点摸不着头脑了,序列化时CaptchaField不管作用,百度搜索也没找到相应的办法,于是心想只有重写restframework_jwt自带的登录验证接口及注册接口,都得新增字段。

二.django-simple-captcha简单介绍

  Django Simple Captcha是一个非常简单但高度可定制的Django应用程序,可以将captcha图像添加到任何Django表单中。

  网址如下:https://django-simple-captcha.readthedocs.io/en/latest/,只需按照文档简单配置即可,该插件会对应生成一张表,存放验证码信息及过期时间等。

三.基于django-simple-captcha的drf图片验证码

  1.生成图片验证码接口(我这里将图片转换成了base64),也可以是图片或地址:

from django.http import HttpResponse
from captcha.views import CaptchaStore, captcha_image
import base64
.......
class ImageView(APIView):
def get(self, request):
hashkey = CaptchaStore.generate_key()
try:
#获取图片id
id_ = CaptchaStore.objects.filter(hashkey=hashkey).first().id
imgage = captcha_image(request, hashkey)
#将图片转换为base64
image_base = base64.b64encode(imgage.content)
json_data = json.dumps({"id": id_, "image_base": image_base.decode('utf-8')})
except:
json_data = None
return HttpResponse(json_data, content_type="application/json")

  2.注册时的图片验证码:

    2.1序列化:

    这里把图片验证码的id和用户输入的内容都传过来,不易错误,captcha生成的表中的字段expiration是生成图片的时间加五分钟,因此captcha判断的也就是这个过期时间,重写也可以判断这个时间,若当前时间大于它则过期(有效时间五分钟)。

class UserRegSerializer(serializers.ModelSerializer):
""""
用户注册序列化
"""
username = serializers.CharField(min_length=2, max_length=20,
error_messages={
"max_length": "用户名长度应小于等于20",
"min_length": "用户名长度应大于等于2"},
validators=[UniqueValidator(queryset=User.objects.all(), message='用户名已经被使用')],help_text="用户名")
code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label='验证码',
error_messages={
"blank": "请输入邮箱验证码",
"required": "邮箱验证码不能为空",
"max_length": "邮箱验证码格式错误",
"min_length": "邮箱验证码格式错误"
}, help_text='邮箱验证码')
email = serializers.CharField(required=True, allow_blank=False,
validators=[UniqueValidator(queryset=User.objects.all(), message='用户已经存在')],help_text="邮箱")
password = serializers.CharField(style={"input_type": "password"}, write_only=True,help_text="密码")
captcha = serializers.CharField(min_length=4, max_length=4, required=True,
error_messages={
"max_length": "图片验证码格式错误",
"min_length": "图片验证码格式错误",
"required": "请输入图片验证码"
},help_text="图片验证吗")
ima_id = serializers.CharField(required=True, write_only=True, allow_blank=False,help_text="图片验证码id") def validate_code(self, code):
verify_codes = EmailVeriyRecord.objects.filter(email=self.initial_data['email']).order_by('-send_time')
if verify_codes:
last_verfycode = verify_codes[0]
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
if five_minute_ago > last_verfycode.send_time:
raise serializers.ValidationError('验证码过期')
if code != last_verfycode.code:
raise serializers.ValidationError('验证码错误')
else:
raise serializers.ValidationError('验证码错误') def validate_password(self, password):
"""
密码长度大于6小于12
"""
if re.match(REGEX_PWD, password):
pass
else:
raise serializers.ValidationError("密码必须包含数字,字母,特殊符中两到三种,且长度在6-12之间")
return password def validate_captcha(self, captcha):
try:
captcha = captcha.lower()
except:
raise serializers.ValidationError("图片验证码错误")
image_code = CaptchaStore.objects.filter(
id=self.initial_data['ima_id']).first()
if image_code and datetime.now() > image_code.expiration:
raise serializers.ValidationError('图片验证码过期')
else:
if image_code and image_code.response == captcha:
pass
else:
raise serializers.ValidationError("图片验证码错误") # 作用于所有字段
def validate(self, attrs):
if attrs['username']:
pass
else:
attrs['username'] = attrs['email']
del attrs["code"]
del attrs["ima_id"]
del attrs["captcha"]
return attrs class Meta:
model = User
fields = ('email', 'code', 'password', 'username', 'captcha', 'ima_id')

    2.2注册view实现:

class UserRegisterViewset(mixins.CreateModelMixin, mixins.UpdateModelMixin,
mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""
用户注册接口
create:
用户添加
"""
serializer_class = UserRegSerializer
queryset = User.objects.all()
authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication) def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
re_dict = serializer.data
payload = jwt_payload_handler(user)
re_dict['token'] = jwt_encode_handler(payload)
headers = self.get_success_headers(serializer.data)
return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) def get_serializer_class(self):
'''
重载GenericAPIView中的get_serializer_class函数,调用不同的序列化类,如果是create,
就调用UserRegSerializer序列化,否则UserDetailSerializer序列化
:return:
'''
if self.action == 'retrieve':
return UserDetailSerializer
elif self.action == 'create':
return UserRegSerializer
return UserDetailSerializer def get_permissions(self):
'''
重载APIview中的get_perimissions函数,如果是新增用户则不用登录,否则必须登录
:return:
'''
if self.action == 'retrieve':
return [permissions.IsAuthenticated()]
elif self.action == 'create':
return []
return [] def get_object(self):
'''
返回当前用户
:return:
'''
return self.request.user def perform_create(self, serializer):
return serializer.save()

  2.登录:

    2.1序列化:

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from django.contrib.auth import authenticate
from rest_framework_jwt.compat import PasswordField class MyloginSerializer(JSONWebTokenSerializer):
"""
从写登录序列化
""" def __init__(self, *args, **kwargs):
"""
Dynamically add the USERNAME_FIELD to self.fields.
"""
super(JSONWebTokenSerializer, self).__init__(*args, **kwargs) self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField(write_only=True)
self.fields['captcha'] = serializers.CharField(min_length=4, max_length=4, required=True,
error_messages={
"max_length": "图片验证码格式错误",
"min_length": "图片验证码格式错误",
"required": "请输入图片验证码"
})
self.fields['ima_id'] = serializers.CharField(required=True, allow_blank=False) def validate_captcha(self, captcha):
image_code = CaptchaStore.objects.filter(
id=self.initial_data['ima_id']).first()
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
if image_code and five_minute_ago > image_code.expiration:
raise serializers.ValidationError('验证码过期')
else:
if image_code and (image_code.response == captcha or image_code.challenge == captcha):
pass
else:
raise serializers.ValidationError("图片验证码错误") def validate(self, attrs):
del attrs["ima_id"]
del attrs["captcha"]
credentials = {
self.username_field: attrs.get(self.username_field),
'password': attrs.get('password')
} if all(credentials.values()):
user = authenticate(**credentials) if user:
if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg) payload = jwt_payload_handler(user) return {
'token': jwt_encode_handler(payload),
'user': user
}
else:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg)
else:
msg = _('Must include "{username_field}" and "password".')
msg = msg.format(username_field=self.username_field)
raise serializers.ValidationError(msg)

    2.2view:

from rest_framework_jwt.views import JSONWebTokenAPIView
from .serializers import MyloginSerializer class MyJSONWebToken(JSONWebTokenAPIView):
""""
重写jwt的登录验证,含图片验证码
"""
serializer_class = MyloginSerializer

  3.url中相应配置:

    url(r'images/$',ImageView.as_view()),
url(r'login/$',MyJSONWebToken.as_view(),name="login")

四.总结

  这样做功能是实现了,但感觉有些粗糙,可以把验证码表的数据超过某个时间的自动清除,也可以把数据放入缓存(redis等),希望能提一些改进的建议。

drf实现图片验证码功能的更多相关文章

  1. 纯JS实现图片验证码功能并兼容IE6-8

    最近要搞一个图片验证码功能,但是又不想自己写后台代码.于是自己准备搞一个纯前端的验证码功能,于是网上搜索了一下,找到一个插件gVerify.js,简单好用,实现完美.不过后面接到说要兼容IE8,想想也 ...

  2. Springboot +redis+⾕歌开源Kaptcha实现图片验证码功能

    Springboot +redis+⾕歌开源Kaptcha实现图片验证码功能 背景 注册-登录-修改密码⼀般需要发送验证码,但是容易被 攻击恶意调⽤ 什么是短信-邮箱轰炸机 手机短信轰炸机是批.循环给 ...

  3. 用Java实现图片验证码功能

    一.什么是图片验证码? 可以参考下面这张图: 我们在一些网站注册的时候,经常需要填写以上图片的信息. 1.图片生成实体类: package com.hexianwei.graphic; import ...

  4. 【Spring】基于SpringMVC的图片验证码功能实现

    后台实现代码: ImgController.java 文件 package cn.shop.controller; import java.awt.Color; import java.awt.Fon ...

  5. Lumen 实现接口 Captcha图片验证码功能

    安装 composer require youngyezi/captcha 使用 新版的包已经删除了 session 支持,完全交给业务自由选择存储方式 个人觉得这样更方便来解耦业务,尤其 Lumen ...

  6. django网页图片验证码功能

    在一个正常的登录系统中,验证码是非常重要的,用于识别人机,毕竟我们都知道,这个世界中存在着万恶的爬虫,验证码有很多种方式,有图片的,有邮件的,有短信的,有拼图的,不管什么样的验证码,目的都是验证访问用 ...

  7. Lumen5.7快速实现Captcha图片验证码功能

    公司发送短信注册的接口需要防刷,需要一个图形验证码,不考虑收费产品. Lumen5.7+nginx+mysql 使用了这个作者的扩展包,只讲实现.https://github.com/Youngyez ...

  8. WebSite---前台系统图片验证码心得

    背景: 因为移动端APP和Msite手机注册发送短信验证码没有添加图片验证码功能.公司的短信接口被恶意刷取.所以我们就觉得在移动端添加一个图片验证码功能.分享一下大体实现方式思路.PS demo是自己 ...

  9. Spingmvc项目注册登录图片验证码(比较灵活的验证码)

    最近项目中注册模块要加一个图片验证码功能. 写下来记录下. 1:首先用什么实现,我用的servlet. 后台java代码:RandomValidateCode 类 ,这个类是生成随即验证码和干扰线,可 ...

随机推荐

  1. flask上传excel文件,无须存储,直接读取内容

    运行环境python3.6 import xlrd from flask import Flask, request app = Flask(__name__) @app.route("/& ...

  2. 无备份时用dbms_repair恢复坏块的方法

    份的情况下可以直接使用备份来恢复. 对于通过备份恢复,Oracel为我们提供了很多种方式,冷备,基于用户管理方式,RMAN方式等等. 对于这几种方式我们需要实现基于数据库以及文件级别的恢复.RMAN同 ...

  3. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  4. 用 Django 管理现有数据库

    在多数项目中,总有一些几乎一成不变的 CRUD 操作,编写这些代码很无聊,但又是整个系统必不可少的功能之一.我们在上一个项目中也面临类似的问题,虽然已经实现了一个功能相对完整的管理后台,也尽量做到了代 ...

  5. mybatis源码-原来resultMap解析完是这样

    目录 1 两个基础类 1.1 列映射类ResultMapping 1.2 结果集映射类ResultMap 2. 解析 2.1 入口函数 2.2 解析流程 2.3 获取 id 2.4 解析结果集的类型 ...

  6. Jenkins-job之间依赖关系配置

    使用场景: 想要在某APP打新包之后,立即执行自动化测试的job来验证该新包. 比如Job A 执行完执行Job B ,如下图所示,如何建立依赖呢? 1.配置上游依赖 构建触发器-配置如下信息: 选择 ...

  7. BZOJ1969 航线规划

    给定一个无向图,每次删除一条边,求每次有多少关键边.一条边是关键边,当且仅当从1到n的所有路径都包含这条边.所有时刻图都联通. 考虑倒着做.相当于给一棵树,每次加一条边,这样树上这条边的两个端点间的路 ...

  8. 解析vue2.0的diff算法 虚拟DOM介绍

    react虚拟dom:依据diff算法台 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快 ...

  9. C. Nastya Is Transposing Matrices

    链接 [https://codeforces.com/contest/1136/problem/C] 题意 给你两个规模一样的矩阵 问是否可以通过不断选取A矩阵的子"方正"转置得到 ...

  10. 【评分】Alpha 事后诸葛亮(团队)

    [评分]Alpha 事后诸葛亮(团队) 总结 按时交 - 有分 晚交 - 0分 迟交一周以上 - 倒扣本次作业分数 抄袭 - 倒扣本次作业分数 本次作业都是以问答形式进行,大部分同学在回答问题方面都一 ...