前后端分离图片验证码实现方案详解
1. 获取图片验证码接口
{
"status": 1,
"message": "ok",
"data": {
"base64": "data:image/png;base64,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",
"key": "$2y$10$Xf3t5ZLfTXYo19sIFGZUcum42GemJLCLv.gVS6gf7NKn2.NzHHmxa",
"md5": "c2527ca3bdbe4b9cac126583ffc51a74"
}
}
后端接口在返回这些值的时候需要把这些值记录下,可以缓存在文件里面,可以放到mysql里面也就是创建一个表,也可以放到redis里面,如果缓存入文件,不支持负载均衡横向扩展,或者是那种定期销毁的实例比如容器。如果放到mysql关系型数据库里面的话,性能会有些影响,如果放到redis里面,并且设置一个生存时间是最优方案。
表字段
base64(base64图片码,非必要)
key (返回给客户端,需要验证的时候客户端提交过来,uuid不能重复即可,必要)
md5 (md5真实验证码,后转小写,非必要)
real_img_code (真实验证码,必要)
times (错误次数,根据业务错误几次后,这条记录失效,需要重新获取新的记录,非必须)
expire_time (过期时间,一个验证阿码,获取之后超过多久就失效,需要重新获取,非必须)
add_time (添加时间,和过期时间一样都可以做过期业务逻辑处理非必须)
后端接口返回如上图的json数据,data里面的额base64是图片base64编码后的。前端拿到后放到img的src值里面。Key参数是后端验证验证码的时候需要传入的。md5是md5(验证码)后转小写的值,用于前端自行验证验证码是否正确,比如光标离开验证码输入框之后,谨记只做类似这样的验证,最后验证码的校验肯定是后端接口验证的,如果只是前端校验证码的正确性就是在耍流氓。这样的验证码只能让人类输入验证码,无法阻碍爬虫。因为可以通过程序直接把数据发送给后端接口。单纯的前端验证是伪科学。
一定要注意千万不要把真实的验证码 real_img_code 返回给前端。否则就失去了验证码意义。因为有些人可能感觉我直接把真实的返给前端,可以让他自己做本地验证。或者说给前端返回一个aes加密的后的验证码,然后前端自己去解密。前端可以查看源码,意味着加密算法是公开的,aes这种对称加密,秘钥也没法在前端隐秘保存。所以行不通。秘钥不能放到前端。那有人说了那我搞个rsa加密,把公钥给前端,私钥在服务器接口服务器。不管是对称加密的秘钥还是非对称加密的公钥,只要是放到前端就意味着别人能看到,就意味这不安全。给前端返回的图片验证码的md5值,说白了也只是在某些场景下,前端自己验证码客户输入的验证码是否正确。最终图片验证码的正确性肯定还是后端验证的,先验证验证码,然后做业务逻辑处理。
2. 验证图片验证码接口
前端通过上面的接口获取到图片验证码以及key,如果需要做js验证验证码正确或者错误的业务逻辑可以使用md5那个值,做个本地校验,如果没有就直接略过。然后把验证码展示在页面上,客户根据图片上面的验证码,在input框里面输入用眼睛识别的验证码。然后在把上面接口获取到的key,连同用眼睛识别出来的图片验证码,一同发送给验证验证码的接口。结合实际的业务,比如会员注册,还会把客户输入的账号和密码发送给后端,如果是手机号获取短信验证码,同时还会把手机号发送给后端接口。我们拿获取手机号验证码举例子说明。
获取手机验证码接口:
给后端发送过去的数据:key 图片验证码img_code 手机号phone(业务参数)
后端接受到这三个参数,第一步先根据key找到对应之前存好的实际的图片验证码那条记录,如果不存在,则报错,如果存在,先判断这条记录里面的错误次数times字段,如果超过指定值比如4次,就直接报错,然后在看下有效期expire_time字段,如果过期了也提示错误,如果都正常,判断下验证码字段是否正确,如果不正确则增加times错误次数,如果正确则校验通过,删除这条记录,走后面的业务逻辑处理,比如 调用通过手机号发送短信验证阿码接口等其他逻辑。这里如果验证码错误,前端可以再次调用获取验证码接口获取一个新的,更新本地的key,以及图片的src。
版权声明:若无特殊注明,本文皆为《菜鸟站长》原创,转载请保留文章出处。
本文链接:前后端分离图片验证码实现方案详解 - https://wziyi.net/?post=361