1. 场景描述
或许是近年来电话推销机器人太泛滥了,常常搞得正常的电话销售“灰头土脸”。有人为了验证对方究竟是人还是机器,竟想出来各种各样的奇葩手段。最近一小伙接到了一个汽车推销电话,但他听声音无法判断对方是不是人工客服人员。尽管对方在电话里反复声称自己是“真人”,可男子还是不肯相信,竟然提出让客服人员即兴背诵唐诗《陋室铭》,以此证明自己不是人工智能机器人,令人啼笑皆非。其实在这个场景中涉及一个重要而核心的问题,那就是如何进行身份认证。
我们现在生活在一个网络时代,身份认证也算是司空见惯的事情。例如:如果你需要修改手机银行登录密码,那么你就要通过获取短信验证码来证明自己的身份;如果你忘记了邮箱登录密码,你需要向邮箱运营方申请验证码,以便重置邮件系统的登录密码;使用验证码来验证身份的场景比比皆是。在这些认证场景中,验证码就是我们获取特殊权限的通行证,以此证明:你是谁?从哪里来?要到哪里去?你可千万别小看这三个问题,这是哲学研究的三大终极问题。
接下来,我们就来谈一谈验证码的事儿,如何生成验证码以及怎样进行验证码的校验。
2. 编程思路
总体来讲,我们常见的验证码可分为纯数字验证码以及由字母数字和特殊字符组成的字符验证码。顾名思义纯数字验证码由数字0~9组成的多位的数字串。本场景中我们讲解纯数字验证码的生成和验证。
2.1 随机生成验证码
我们可以在字符串“1234567890”中随机抽取4个字符,组成一个新的字符串,这个就是一个数字验证码。
2.2 验证码的实效性
出于安全性原因,每个验证码都有一个实效性要求,也就是说验证码在一定的时间范围内才是有效的。因此我们可以在创建验证码的同时,生成一个时间戳,便于在验证码校验时与当前时间进行比较。这里我们把验证码的生命周期设定为5分钟。
2.3 如何验证验证码
双重校验。既要校验验证码的正确性,又要校验验证码的有效期。
3. 程序代码
程序由两个模块组成。一个是验证码函数基础模块verification_code.py,它是存放在Python包common中;另一个是主程序,演示验证码函数的各种使用方法verification_test.py。
下面是模块verification_code.py的源程序代码:
"""
verification_code.py : 验证码基础函数模块
"""
import time
import random
def make_code(length=4):
"""
功能:随机生成验证码
参数:length 验证码长度
"""
digitals = '0123456789'
code = ''
for i in range(length):
idx = random.randint(0, len(digitals)-1) # ①
code += digitals[idx] # ②
return code
def check_code(code_dict, code, timeout=5):
"""
功能:校验验证码
参数:code_dict 验证码字典
code 验证码
timeout 验证码有效期,单位为分钟
"""
status = 0
period = timeout * 60 # ③
time_stamp = time.time() # ④
if code not in code_dict:
status = 1 # 验证码无效
else:
if (time_stamp-code_dict[code]) > period: # ⑤
status = 2 # 验证码超时
else:
status = 0 # 验证码正确
return status
def add_code(code_dict, code):
"""
功能:将验证码保存到字典
参数:code_dict 存放验证码字典
code 验证码
"""
code_dict[code] = time.time() # ⑥
重要函数说明如下:
函数make_code(length=4):缺省默认情况下,生成一个4位数字的验证码。
函数check_code(code_dict, code, timeout=5):校验验证码。默认情况下验证码的有效期是5分钟。
函数add_code(code_dict, code):将验证码code加入到验证码字典中。
重要语句说明如下:
语句①随机生成字符串:'0123456789’中的一个索引值。
语句②根据索引值idx提取字符串:'0123456789’中的一个字符。
语句③将验证码有效期的分钟转换成秒数。
语句④生成当前时间的时间戳。
语句⑤校验验证码是否过期。
语句⑥创建一个字典项,它是以验证码是键,时间戳是值。
以下是模块verification_test.py程序代码:
"""
verification_test.py : 趣谈验证码
"""
from common.verification_code import *
def print_status(status):
if status == 0:
print("验证码正确!")
elif status == 1:
print("验证码错误!")
elif status == 2:
print('验证码过期!')
def main():
code_dict = {} # 验证码字典
for i in range(3): # 生成 3 个验证码
code = make_code() # 4位数字验证码
time.sleep(1)
add_code(code_dict, code)
# 打印生成的验证码和时间戳
print('验证码', '\t', '时间戳')
for k, v in code_dict.items():
print(k, '\t', v)
# 取字典中第1个键
code = list(code_dict.keys())[0]
status = check_code(code_dict, code)
print_status(status)
time.sleep(360) # 延时6分钟
status = check_code(code_dict, code, timeout=5)
print_status(status)
status = check_code(code_dict, 'A345')
print_status(status)
if __name__ == '__main__':
main()
4. 执行效果
4.1 目录结构
本程序由两个模块构成,它们存放的目录如下:
D:\cases\趣谈验证码>dir
2022/12/20 16:28 <DIR> common
2022/12/20 16:21 1,033 verification_test.py
D:\cases\趣谈验证码>cd common
D:\cases\趣谈验证码\common>dir
2022/12/20 16:28 1,179 verification_code.py
2022/04/01 07:34 106 __init__.py
(cases) D:\cases\趣谈验证码\common>
目录common实际上是Python的包,因为在该目录下有一个特殊文件__init__.py。
4.2 代码执行
D:\cases\趣谈验证码>python verification_test.py
验证码 时间戳
8444 1671526895.0580647
7538 1671526896.0734143
2305 1671526897.085462
验证码正确!
验证码过期!
验证码错误!
D:\cases\趣谈验证码>
程序执行的显示结果表明,分别测试了验证码校验中存在的三种情况:即验证码正确、错误和过期,程序处理结果完全正确。
5. 场景扩展
以上程序展示了数字验证码的生成和校验。作为本案例的延伸和扩展,我们还可以增加字符验证码的生成和校验功能,请读者自行完成。