接了一个等保三级的需求,代码写的很顺利,本地自测的时候出现了各种问题,在这记录一下
需求
简单说一下就是在登录时加一个手机验证码校验,当登录失败超过五次时,出现滑块验证(就是大家平常见的那种),登录成功后失败次数清零。
关键点
验证顺序:
- 验证滑块
- 验证用户名密码
- 验证短信验证码
我最开始写的逻辑是先验证用户名密码,这样做是不对的。因为本身是为了防止暴力破解密码,用户名密码都验证对了,再去验证滑块是没有意义的!
记录错误次数的时机
- 账号密码输入错误
后端验证码不存在/未生成输入验证码错误验证码过期
删除线的部分是产品告知不要累加错误次数,但我个人最开始是认为需要记录的
后端做必要的发送短信时间间隔和次数限制
由于这个接口调用是不是需要token的(未登录时获取验证码),所以要避免别人恶意消耗短信资源,后端需要做60秒内不能重复发送和一天内一个用户的短信上限条数限制(后者这次需求里我没做)
登录成功后,验证码失效/删除
这个点也是我最初遗漏的,后来参照了一下百度,登录成功后是无法用之前的短信验证码再登录的,当然有的系统在验证码有效期内是可以重复登录。我后端登录成功后,直接将之前的验证码数据给删掉了,就没法重复登录了。
实现方式
- 两张表,一张记录登录用户的短信验证码信息,一张记录登录用户的失败次数
- 通过实现AuthenticationProvider接口的authenticate方法,在里面做的校验。校验不通过直接抛出OAuth2Exception
- 为防止抛异常回滚数据,通过使用mq记录用户登录失败次数
改善点
上述方案是同事提前给设计好的,但是我在开发过程中,还是发现了一些可以优化的点
需要记录的信息是短信验证码和失败次数,先说短信验证码,它有以下几个特点:
- 60秒的时效性(已经存在60秒的验证码可视为过期数据)
- 可能会被高频查询(登录检查是否存在,已存在不会重复发送,避免浪费短信资源和造成短信轰炸的现象)
- 从发送(增)到登录验证(查)时间可能会很短
- 没有必要作为持久化数据存储
再说失败次数的特点,我们的业务需求是失败超过5次,半小时内登录一直弹出滑块,检索的逻辑是判断更新时间字段(半小时内)及失败次数(>=5),记录失败次数逻辑:是根据用户名取出这条记录的更新时间,如果是在半小时内则累加失败次数,否则失败次数置为1。
其实说到这,大家都能看出利用redis高检索性能,数据自动过期的功能,能更好的实现这个功能。使用MySQL,我写了大量的业务代码去判断是否过期,和对过期数据操作的代码…
其他小问题
自测时调用/oauth/token出现401
org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
调用接口时需要在Header加上Authorization