多次输错密码后如何禁止一定时间内用户再次登录
通常使用 IP 地址为单位来进行限制,而非具体的用户。这样可以减少误伤其他用户的可能性。
(一个非法用户可能会拿他人的账号不断尝试登录)
同时,以 IP 地址为单位进行限制还可以避免黑客通过使用同-IP 地址进行暴力破解等攻击行为。提高系统的安全性和稳定性。
使用 Redis解决该问题
使用 Redis 记录当前 ip 的尝试登录次数:
·key 为该 ip 请求登录的唯一标识
·value 为当前 ip 的尝试登录次数。
需要给 key 设置一个过期时间,用来实现指定时间内无法再次登录的效果。并且,每次
对 key 对应的 value 进行修改时,都需要重置过期时间。
大致运行流程如下:
- 当用户登录时,判断是否有对应的 key
- 如果没有对应 key ,说明是第一次登录,如果密码出错,就创建对应的 key,key 对应的 value 值为设为1
- 如果有对应的 key,说明不是第一次登录了,需要判断 key 对应的 vaue 大小是否小于 3。
- 如果小于3则代表还能继续尝试登录,重复密码校验这一步。如果密码继续出错,就返回“登录失败”,并将 key 对应的 value值加1
- 如果 value 等于 3,返回“输入密码错误次数达到 3次,请 xx 分钟后再尝试”
多线程抢夺共享资源情景(多位用户抢一个红包,如何保证只有一个抢到?)
为了共享资源被安全地访问,需要对共享资源进行加锁
实际生产项目多为分布式环境,分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。于是,分布式锁 就诞生了。
分布式锁常用Redis实现
什么是分布式缓存
如何基于 Redis 实现一个最简易的分布式锁?
在 Redis 中, SETNX
命令是可以帮助我们实现互斥。SETNX
即 SET if Not eXists,如果 key 不存在的话,才会设置 key 的值
> SETNX lockKey uniqueValue
(integer) 1
> SETNX lockKey uniqueValue
(integer) 0
释放锁的话,通过 DEL
命令删除对应的 key 即可。
> DEL lockKey
(integer) 1
为了防止误删其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。
选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证锁释放操作的原子性
java">// 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end