- 发送通知:
client端:客户输入contact info(Email Address / Mobile Number)
server端:
在发送之前处理数据,判断:
是否满足发送频率次数(10 s内只能发一次)
是否验证失败次数已超过要求(只能允许4次验证失败,再失败就不允许该用户再次发送)
在判断满足条件的基础之上,得到:
根据用户guid+currentTimeMills(也被叫做发送时间sendDateTime)生成的当前用户的secret
面对client端验证码有效的时间间隔(mobile 30s,email 600s)(其实server端真正的有效时间间隔是client端的2倍)
根据TOTP的HMAC SHA1算法(hash-based Message Authentic Code),结合secret和interval,生成的动态验证码
根据要求得到的发送消息的模板template
整合好信息后,通过项目签约的ICCM第三方发送消息服务接口,将消息发送给用户。
设计到的代码:
依赖的jar包:
<dependency>
<groupId>org.jboss.aerogear</groupId>
<artifactId>aerogear-otp-java</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
方法参数 secret(guid+sendDateTIme), interval (clock.getCurrentInterval()).生成动态验证码。
调用第三方服务接口,配置参数:
host,port,
TLS/SSL参数配置:keystore证书,密码
超时时间,
header头:代理id/secret等信息
apiPath:请求路径
apiMethod:请求方法
2.验证:
用户收到信息,client端发来填写的动态验证码
在server端验证动态码之前,判断:
是否有发送信息的动作(记录发送时间sendDateTime是否为空)
是否超过失效时间(发送时间和时间间隔相加与当前时间比较)
是否超过验证次数(失败次数已经超过要求)
在判断满足条件的基础之上,得到:
guid+sendDateTime组成的secret(一个作用是用来标识唯一用户,另一个作用是用来匹配发送时的secret进行验证比较。延申一下,如果说,考虑并发,要将数据放入redis缓存中,则key设为secret值,动态验证码为value值)
有效时间间隔
输入的验证码
根据TOTP调用verify方法验证动态验证码
其中有个点,提一下:
Totp类中,DELAY_WINDOW:默认为1,确保client端和server端有交互有延时的时候,server端验证可以多等一个时间间隔的时间(这也就说明了在之前说到的client有效时间一般默认情况下,比server端有效时间少一半)。
另外,在Totp验证过程中,不存在失败叨叨次数自动失效的语法糖。如果说,在缓存中处理,需要加入计数器,确保在失败到达次数限制,对缓存进行失效处理。
延申部分:来自ThoughtWorks 洞见:https://insights.thoughtworks.cn/sms-authentication-login-api/
对于发送暴击问题,故意消耗短信发送配额。结合自身项目使用,我们做了一层简单的处理,限制只允许10s发送一次,文章中的做法是,加图片验证码,在发送短信之前,先验证图形验证码是否正确。
其中,还提出,
在非生产环境上(开发/测试环境),采用白名单机制,确保不会打扰到真实用户。
在特定环境上,确保可以禁用短信验证码的发送,比如PT时,AutoTest时,或者在节约短信配额时。
确保打印日志中,不包含动态验证码的数据信息。