当前位置:网站首页>Redis - 利用lua脚本控制密码错误次数超限,锁定账号

Redis - 利用lua脚本控制密码错误次数超限,锁定账号

2022-08-10 22:30:00 技术日志

Lua脚本:是一种Redis脚本语言,功能和管道类似,客户端可以批量向服务端发送多条语句;不过Lua脚本发送的语句间具备原子性,而管道发送的语句间不具备原子性。

Lua脚本代码: 将代码存于resource --> loginFailLimit.lua文件中;

local key = KEYS[1]
local limit = tonumber(ARGV[1])        ----> 设置限制的次数
local limitTime = tonumber(ARGV[2])    ----> 设置限制的时间
local lockTime = tonumber(ARGV[3])     ----> 账号锁定时间
local current = tonumber(redis.call('get', key) or '0')

-- 每limitTime时间内错limit次, 则账号锁定lockTime时间;
if(current == 0) then
    redis.call('incrBy', key,"1");
    redis.call('expire', key, limitTime);
    return 0;
elseif (current < limit) then
    redis.call('incrBy', key,"1");
    return 0;
elseif (current == limit) then
    redis.call('incrBy', key, "1");
    redis.call('expire', key, lockTime);
    return 1;
else
    return 1;
end;

配置DefautRedisScript:

    @Bean
    public DefaultRedisScript<Boolean> redisScript() {
        DefaultRedisScript<Boolean> objectDefaultRedisScript = new DefaultRedisScript<>();
        objectDefaultRedisScript.setResultType(Boolean.class);
        objectDefaultRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("loginFailLimit.lua")));
        return objectDefaultRedisScript;
    }
创建常量类:
public class RedisConstant {
    public final static String LIMIT = "5"; //失败n次后锁定:
    public final static String LIMIT_TIME = "600"; //时间范围:单位/秒
    public final static String LOCK_TIME = "600"; //账号锁定时间: 单位/秒
}

创建RedisUtil工具类:

@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private DefaultRedisScript redisScript;


    /**
     * 获取key锁定状态:
     * @param key
     * @return true-锁定; false-未锁定;
     */
    public Boolean getLockState(String key) {
        return (Boolean) redisTemplate.execute(redisScript,
                Arrays.asList(key),
                RedisConstant.LIMIT, RedisConstant.LIMIT_TIME, RedisConstant.LOCK_TIME);

    }

    /**
     * 获取key剩余锁定时间:
     * @param key
     * @return
     */
    public long getLockInvalidTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 获取key的值:
     * @param key
     * @return
     */
    public String getValueByKey(String key) {
        return redisTemplate.opsForValue().get(key);
    }
}

测试:

@SpringBootTest
class RedisLuaApplicationTests {
    @Autowired
    private RedisUtil redisUtil;
    final String LOGIN_KEY = "PASSWORD_ERROR_KEY_";

    @Test
    void contextLoads() {
        //模拟密码错误:
        if (true){
            String key = LOGIN_KEY + "userId";
            Boolean flag = redisUtil.getLockState(key);
            if (flag){
                long lockInvalidTime = redisUtil.getLockInvalidTime(key);
                System.out.println("密码频繁错误,已被锁定!请"+lockInvalidTime+"秒后重新登陆或者联系系统管理员!");
                return;
            }
            String value = redisUtil.getValueByKey(key);
            int i = Integer.parseInt(RedisConstant.LIMIT) - Integer.parseInt(value);
            System.out.println("密码错误,剩余"+i+"次机会");
            return;
        }
    }
}

 

原网站

版权声明
本文为[技术日志]所创,转载请带上原文链接,感谢
https://blog.csdn.net/luan666/article/details/126249039