赞
踩
django-simple-captcha
pip install django-simple-captcha
INSTALLED_APPS = [
……
'captcha',
]
python manage.py migrate
数据库迁移相关命令:
python manage.py makemigrations
是用于检测app/models.py的改动,console会告知create model xxx
python manage.py migrate
将上述改动翻译成sql并去数据库执行
验证码模型源码地址:venv/Lib/site-packages/captcha/models.py
from captcha.conf import settings as captcha_settings from django.db import models from django.utils import timezone from six import python_2_unicode_compatible from django.utils.encoding import smart_text import datetime import hashlib import logging import random import time # Heavily based on session key generation in Django # Use the system (hardware-based) random number generator if it exists. if hasattr(random, 'SystemRandom'): randrange = random.SystemRandom().randrange else: randrange = random.randrange MAX_RANDOM_KEY = 18446744073709551616 # 2 << 63 logger = logging.getLogger(__name__) @python_2_unicode_compatible class CaptchaStore(models.Model): challenge = models.CharField(blank=False, max_length=32) response = models.CharField(blank=False, max_length=32) hashkey = models.CharField(blank=False, max_length=40, unique=True) expiration = models.DateTimeField(blank=False) def save(self, *args, **kwargs): self.response = self.response.lower() if not self.expiration: self.expiration = timezone.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT)) if not self.hashkey: key_ = ( smart_text(randrange(0, MAX_RANDOM_KEY)) + smart_text(time.time()) + smart_text(self.challenge, errors='ignore') + smart_text(self.response, errors='ignore') ).encode('utf8') self.hashkey = hashlib.sha1(key_).hexdigest() del(key_) super(CaptchaStore, self).save(*args, **kwargs) def __str__(self): return self.challenge def remove_expired(cls): cls.objects.filter(expiration__lte=timezone.now()).delete() remove_expired = classmethod(remove_expired) @classmethod def generate_key(cls, generator=None): challenge, response = captcha_settings.get_challenge(generator)() store = cls.objects.create(challenge=challenge, response=response) return store.hashkey @classmethod def pick(cls): if not captcha_settings.CAPTCHA_GET_FROM_POOL: return cls.generate_key() def fallback(): logger.error("Couldn't get a captcha from pool, generating") return cls.generate_key() # Pick up a random item from pool minimum_expiration = timezone.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_GET_FROM_POOL_TIMEOUT)) store = cls.objects.filter(expiration__gt=minimum_expiration).order_by('?').first() return (store and store.hashkey) or fallback() @classmethod def create_pool(cls, count=1000): assert count > 0 while count > 0: cls.generate_key() count -= 1
数据库表结构如下:
Django的captcha没有用session对验证码进行存储,而是在数据库中生成一张表进行存储。页面加载时数据库生成一条关于验证码的记录。当提交表单时post到服务器,此时服务器验证captcha_captchastore表中的hashkey对应的response是否与输入的验证码一致。(看起来验证过程是自动完成的,在封装好的第三方库,所以后台代码也不需要处理验证码的验证工作)
urlpatterns = [
path ('captcha/', include ('captcha.urls')), # 验证码
]
文档:
urlpatterns += [
url(r'^captcha/', include('captcha.urls')),
]
补充url和path的区别:
PATH(2.0):from django.urls import path——第三方框架/模块
URL(1.0):from django.urls import url——自定义模块
#forms.py
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
captcha = CaptchaField()
# views.py
from user.forms import CaptchaTestForm
from django.shortcuts import render
def some_view(request):
if request.POST:
form = CaptchaTestForm(request.POST)
# Validate the form: the captcha field will automatically
# check the input
if form.is_valid():
human = True
else:
form = CaptchaTestForm()
return render(request,'captcha.html', locals())
render_to_response
在现在新的django里面已经不支持,换成render可以使用locals()
返回函数执行到此节点内的所有局部变量将上面新增的some_view方法加到urls路由
# user/urls.py
urlpatterns = [
path ('captcha/', include ('captcha.urls')), # 验证码
……
path('demo',views.some_view),
]
<!--captcha.html-->
<form method='POST'>
{% csrf_token %}
{{ form }}
<input type="submit" />
<button class='js-captcha-refresh'></button>
</form>
参考文档:
一直不知道验证码在前后端分离的时候,接口设计怎么使用,比如需要传什么数据,但是前端传递入口又依赖于django的captcha库,后端才接触captcha,那前端要怎么作用呢?就做了一个像下面一样小白的测试,但是captcha_0(一段输入的哈希值吧)怎么前端怎么拿传给后台呢?
登录表单定义了三个属性(见下个目录的代码),但是从控制台看有四个数据,验证码占两个:captcha_0
(hashkey),captcha_1
(用户输入)。
项目结构大概如下(user是项目的app):
<!--login.html--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <div> <form action="/user/formlogin" method="post"> {% csrf_token %} <!-- 登录表单 --> <div> {{ login_form.user_account.label_tag }} {{ login_form.user_account }} </div> <div> {{ login_form.password.label_tag }} {{ login_form.password }} </div> <!-- 验证码 --> <div> {{ login_form.captcha.errors }} {{ login_form.captcha.label_tag }} {{ login_form.captcha }} </div> <input type="submit" value="确定"> </form> </div> </body> </html>
# forms.py
from django import forms
from captcha.fields import CaptchaField
from django.core.exceptions import ValidationError
from user.models import User
# 登录表单
class UserForm (forms.Form):
user_account = forms.CharField (label="用户名", max_length=128, widget=forms.TextInput (attrs={'class': 'form-control'}))
password = forms.CharField (label="密码", max_length=256,
widget=forms.PasswordInput (attrs={'class': 'form-control'}))
captcha = CaptchaField (label='验证码') # 图片验证码+输入框
# 用户登录,生成token # 接收表单数据 # username 用户名 # password 密码 # user 通过输入的用户名获取的数据库用户 # url:user/formlogin # 返回JSON数据 @csrf_exempt def form_login(request): if request.method == "POST": login_form = UserForm (request.POST) # 自定义登录表单 if login_form.is_valid (): # 确保用户名和密码都不为空 username = login_form.cleaned_data['user_account'] password = login_form.cleaned_data['password'] print (username + password) try: user = User.objects.get (user_account=username) except: return HttpResponse (json.dumps ({'code': '301'})) # 用户不存在 if check_password (password, user.password): # print ('数据库密码是:' + user.password) temp = user token = token_op.create_token (temp) return HttpResponse ( json.dumps ( { 'code': '200', # 成功状态码 'token': token, 'user_id': user.user_id, 'user_account': user.user_account, 'user_url': user.user_url, 'user_name': user.user_name, 'user_gender': user.user_gender, 'email': user.email, 'user_phone': user.user_phone, 'user_credit': user.user_credit, 'status': user.status, } ) ) else: return HttpResponse (json.dumps ({'code': '302'})) # 密码不正确 else: return HttpResponse (json.dumps ({'code': '402'})) # 输入框未填完 else: # login_form = UserForm () # return HttpResponse (json.dumps ({'code': '404'})) # 请求非POST类型 return render(request, 'user/login.html', locals())
path ('formlogin', loginViews.form_login), # html页面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。