回顾
- 1、封装了一个zdppy_captcha框架用于生成验证码
- 2、实现了生成base64格式的验证码
- 3、想要生成一个和zdppy_api能够天然结合的接口,使得使用更简单
使用zdppy_api开发简单接口回顾
python
import api
async def get_captcha(req):
return api.resp.success()
app = api.Api(
routes=[
api.resp.get("/captcha", get_captcha)
]
)
if __name__ == '__main__':
app.run()
接口请求:
使用zdppy_api生成验证码接口
python
import api
import zdppy_captcha as captcha
async def get_captcha(req):
code, img = captcha.get_base64(4)
return api.resp.success({
"img": img,
})
app = api.Api(
routes=[
api.resp.get("/captcha", get_captcha)
]
)
if __name__ == '__main__':
app.run()
简单的分析
目前我们想要生成验证码图片是比较简单的,但是怎么验证?
- 1、如何区分是哪个用户的?
目前的结构,很难区分是哪个用户的,不过我们之前分析过一种比较靠谱的方案。
- 在生成code和img的同时,生成一个key,给前端返回key和img,后端根据key记录code,前端传递key和code,然后进行对比。key必须保证唯一性!!!
改进get_base64这个方法
原来的方法
python
def get_base64(num=4, width=160, height=60):
"""
生成base64格式的随机字符串
建议校验的时候不区分大小写
:param num: 字符串中验证码的个数
:param width: 验证码图片的宽度
:param height: 验证码图片的高度
:return: 真实值,base64图片字符串
"""
# 生成随机字符串
code = random.sample(base_str, num)
# 生成图片验证码对象
image = ImageCaptcha(width=width, height=height)
# 第三种使用方式:生成图片验证码BytesIO
data = image.generate(code)
# 转换为base
base64_str = base64.b64encode(data.getvalue()).decode('utf8')
# 返回
code = "".join(code)
return code, base64_str
python生成uuid的两种方法
python
import uuid
print(uuid.uuid4().hex)
print(str(uuid.uuid4()).replace("-", ""))
改进
增加一个uuid字符串。
python
def get_base64(num=4, width=160, height=60):
"""
生成base64格式的随机字符串
建议校验的时候不区分大小写
:param num: 字符串中验证码的个数
:param width: 验证码图片的宽度
:param height: 验证码图片的高度
:return: 真实值,base64图片字符串
"""
# 生成随机字符串
code = random.sample(base_str, num)
# 生成图片验证码对象
image = ImageCaptcha(width=width, height=height)
# 第三种使用方式:生成图片验证码BytesIO
data = image.generate(code)
# 转换为base
base64_str = base64.b64encode(data.getvalue()).decode('utf8')
# 返回
key = uuid.uuid4().hex
code = "".join(code)
return key, code, base64_str
改进2
验证码的宽度现在是固定,4个验证码和6个验证码的宽度是一样的,不太合理?
应该根据验证码的个数动态的扩展宽度。
python
image = ImageCaptcha(width=40 * num, height=height)
接口改造
增加key返回。
python
import api
import zdppy_captcha as captcha
async def get_captcha(req):
key, code, img = captcha.get_base64(4)
return api.resp.success({
"key": key,
"img": img,
})
app = api.Api(
routes=[
api.resp.get("/captcha", get_captcha)
]
)
if __name__ == '__main__':
app.run()
问题分析
- 1、这个接口实际上可以封装为便捷的接口
- 2、我们现在有验证码了,该怎么校验验证码?
封装便捷接口
python
def get(success, num=4):
"""
获取zdppy_api生成验证码的接口
:param num: 验证码的个数
:param success: api.resp.success 是zdppy_api框架中统一返回成功结果的方法
:return:
"""
async def get_captcha(req):
key, code, img = get_base64(num)
return success({
"key": key,
"img": img,
})
return get_captcha
使用便捷接口
python
import api
import zdppy_captcha as captcha
app = api.Api(
routes=[
api.resp.get("/captcha", captcha.zdppy_api.get(api.resp.success))
]
)
if __name__ == '__main__':
app.run()
简单的总结
目前获取验证码的接口暂时这样基本就够用了。
但是,我们还缺少校验验证码的方法以及接口。
首先我们需要实现校验验证码的方法。
如何校验验证码是否正确?
获取验证码有什么返回值?
- key:唯一标识
- code:验证码的真实值
- img:base64格式的图片
如何校验?
- 传入key和code,如果和库里面的key和code相同,则校验通过!!
要实现这个思路,问题比较多:
- 1、用什么库去存储key和code?
- 2、怎么进行对比
- 3、key需要做过期处理,我们不可能让它一直生效!!!
怎么存储key和code?
用一个全局的字典。
我们知道接口的请求一般都是多线程或者多协程,会产生并发。python的字典,是不是并发安全的?
不是!!!
但是我们对字典的操作通常是复合操作(插入、删除、更新),这些步骤并不是原子性的。在多线程抢占解释器锁时(特别是多核CPU的机器中),就可能会导致数据不一致。因此,字典类型在多线程环境中并不是线程安全的,因为它的操作不满足原子性,需要额外的同步机制(如锁)来保证在多线程环境下的正确使用。
找到了一个值得研究的库
https://grantjenks.com/docs/diskcache/tutorial.html
python
from diskcache import Cache
cache = Cache()
cache.close()
with Cache(cache.directory) as reference:
reference.set('key', 'value')
print(cache.get('key'))