第14章 实战
验证码
目的
区分人与机器
全称叫作:全自动区分计算机和人类的图灵测试(Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码
为了解决暴力登录,垃圾广告等问题。
工作原理
常见的图形验证码是与web中的session相关联的,在一个session开始时,在需要使用验证码的地方会生成一个与当前会话相关的验证码,用户识别出验证码后通过填写表单将数据提交给服务器,服务器端会验证此次会话中的验证码是否正确。具体来说,其工作流程如图1所示:
验证码发送逻辑
手机验证码

手机验证码,代码
from rest_framework import serializersclass SmsSerializer(serializers.Serializer):mobile = serializers.CharField(max_length=11)def validate_mobile(self, mobile):"""验证手机号"""# 手机是否注册if User.objects.filter(mobile=mobile).count():raise serializers.ValidationError("用户已经存在")# 手机号码是否合法if not re.match(setings.REGEX_MOBILE, mobile):raise serializers.ValidationError("手机号码不合法")# 发送时间限制one_mintes_ago = datetime.now()-timedelta(minutes=1)if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile):raise serializers.ValidationError("距离上次发送未超过60秒")return mobile
图形验证码
验证码目录
utilscaptcha_init_.pyCookie-Regular.ttfCourgette-Regular.ttfeuphorig.tffLHANDW.TTFLobster-Regular.ttfverdana.ttf
Pillow 介绍
PIL (Python Image Library) 是 Python 平台处理图片的事实标准,兼具强大的功能和简洁的 API。
安装
pip install Pillow
创建验证码
import randomimport string#Image:一个画布#ImageDraw:一个画笔#ImageFont:画笔的字体from PIL import Image,ImageDraw,ImageFontclass Captcha(object):"""captcha验证码"""number = 4 # 生成几位数的验证码size = (100, 30) # 验证码图片的宽度和高度fontsize = 25 # 验证码字体大小line_number = 2 # 加入干扰线的条数# 构建一个验证码源文本SOURCE = list(string.ascii_letters)for index in range(0, 10):SOURCE.append(str(index))# 绘制干扰线@classmethoddef __gene_line(cls, draw, width, height):begin = (random.randint(0, width), random.randint(0, height))end = (random.randint(0, width), random.randint(0, height))draw.line([begin, end], fill=cls.__gene_random_color(), width=2)# 绘制干扰点@classmethoddef __gene_points(cls, draw, point_chance, width, height):chance = min(100, max(0, int(point_chance))) # 大小限制在[o, 100]for w in range(width):for h in range(height):tmp = random.randint(0, 100)if tmp > 100 - chance:draw.point((w, h), fill=cls.__gene_random_color())# 生成随机的颜色@classmethoddef __gene_random_color(cls, start=0, end=255):random.seed()return (random.randint(start, end), random.randint(start, end), random.randint(start, end))# 随机选择一个字体@classmethoddef _gene_random_font(cls):fonts = [# "Courgette-Regular.ttf",# "Lobster.ttf",# "verdana.ttf","Lobster.ttf",]font = random.choice(fonts)print(font)return "utils/captcha/" + font# 随机生成一个字符串(包括英文和数字)@classmethoddef gene_text(cls, number):# number是生成验证码的位数return "".join(random.sample(cls.SOURCE, number))# 生成验证码@classmethoddef gene_graph_captcha(cls):width, height = cls.size # 验证码图片宽和高# R:Red(红色)0-255# G:G(绿色)0-255# B:B(蓝色)0-255# A:Alpha(透明度)image = Image.new("RGBA", (width, height), cls.__gene_random_color(0, 100))# 验证码的字体font = ImageFont.truetype(cls._gene_random_font(), cls.fontsize)# 创建画笔draw = ImageDraw.Draw(image)# 生成字符串text = cls.gene_text(cls.number)# 获取字体的尺寸font_width, font_height = font.getsize(text)# 填充字符串draw.text(((width - font_width) / 2, (height - font_height) / 2), text, font=font,fill=cls.__gene_random_color(150, 255))# 绘制干扰线for x in range(0, cls.line_number):cls.__gene_line(draw, width, height)# 绘制噪点cls.__gene_points(draw, 10, width, height)with open("captcha.png", "wb")as fp:image.save(fp)return (text, image)
传输验证码
from django.http import HttpResponsedef graph_captcha():#获取验证码text,image=Captcha.gene_graph_captcha()#BytesIo:字节流out=BytesIO()image.save(out,"png")out.seek(0)# flask 响应# resp=make_response(out.read()) # flask 响应对象函数# resp.content_type="image/png"# django 响应resp = HttpResponse(content_type='image/png')resp.content = out_obj.read()return resp# urls.pyurlpatterns = [path('register/', views.UserRegisterView.as_view(), name='register'),path('captcha/', views.graph_captcha, name='captcha')]
使用redis/memcache缓存验证码
import memcachecache=memcache.Client(['127.0.0.1:112111], debug=True)def set(key, value, timeout=60):return cache.set(key, value, timeout)def get(key):return cache.get(Key)def delete(key):return cache.delete(key)
redis 库介绍
redis提供两个类
- StrictRedis:实现了大部分官方的命令,并使用官方的语法
- redis(StrictRedis):向后兼容旧版本的
redis-py
redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接。同理,python的redis没有实现select命令。
import redis# host是redis主机,需要redis服务端和客户端都启动 redis默认端口是6379# decode_responses=True 写入的kv对中的value为str类型,如果不加这个参数,写入的为字节类型redis_cache = redis.Redis(host='localhost', port=6379, decode_responses=True)redis_cache.set('name', 'junxi') # key是"foo" value是"bar" 将键值对存入redis缓存print(redis_cache['name'])print(redis_cache.get('name')) # 取出键name对应的值print(type(redis_cache.get('name')))def set(key, value, timeout=60):return redis_cache.set(key, vlaue, timeout)def get(key):return redis_cache.get(key)def delete(key):return redis_cache.
使用django-redis
django-redis是一个使 Django 支持 Redis cache/session 后端的全功能组件.
django依赖
django-redis 3.8.x 支持 django 1.4, 1.5, 1.6, 1.7 (或许会有 1.8)django-redis 4.4.x 支持 django 1.6, 1.7, 1.8, 1.9 和 1.10
redis server支持
django-redis 3.x.y 支持 redis-server 2.6.x 或更高django-redis 4.x.y 支持 redis-server 2.8.x 或更高
其他依赖
所有版本的 django-redis 基于 redis-py >= 2.10.0.
OAuth
原理
反馈+--------------+ +---------------+| | <------------+ | || 本地应用 | | 第三方应用 || +---------------> | |+------^-------+ 引导用户跳入 +-------+-----^-+| | || | || | || | || 请求第三方登录 响应授权页 | | 用户授权登录| | || | || +-------------+ | || | <-------+ || | 用户 | |+----------+ +---------------++-------------+
开放平台
- 微博开放平台
- 微信开放平台
- QQ开放平台
多帐号登录
user表
| column | type | note |
|---|---|---|
| id | int | 用户id |
| password | varchar | 口令 |
| status | int | 状态 |
| created_at | … | … |
扩展用户表:user_login
| column | type | note |
|---|---|---|
| id | int | 绑定id |
| user_id | int | 用户id |
| type | varchar | phone/useranme/email/wechat_openid |
| account | varchar | 手机/用户名/email |
| create_at | … | … |
地图
名词:
POI Point of interesting
可以翻译为兴趣点,就是在地图上任何非地理意义的有意义的点:比如商店,酒吧,加油站,医院,车站等。不属于poi的是有地理意义的坐标:城市,河流,山峰
