网站推广是什么意思,设计网站导航大全,网上教育培训机构,吴志国网站建设工作室Redislua脚本限制ip多次输入错误密码
不能锁username#xff0c;因为如果有人恶意保留破解密码的话。会导致用户本人无法登录。 这里我采用 以ip的方式进行锁定。利用redis 设置key#xff1a;ip。value#xff1a;当前ip尝试登录的次数 实现逻辑 逻辑简单#xff0c;假设…Redislua脚本限制ip多次输入错误密码
不能锁username因为如果有人恶意保留破解密码的话。会导致用户本人无法登录。 这里我采用 以ip的方式进行锁定。利用redis 设置keyip。value当前ip尝试登录的次数 实现逻辑 逻辑简单假设限制错误次数为5
用户登录时。判断key是否存在。如果key不存在说明第一次登录。判断密码是否正确如果正确什么都不干直接返回。如果不正确设置key为ipvalue为1并设置过期时间返回错误信息。如果存在key说明之前尝试登录过。判断value是否大于阈值如果大于阈值刷新过期 并返回错误。如果小于阈值还要判断密码是否正确。如果密码正确删除key并返回正确信息。如果密码不正确将key的value值1并重置过期时间返回密码错误的信息。
以上主要注意两点 一点是有key的情况下密码正确需要删除key。 二是有key的情况下密码错误或者尝试次数大于阈值再次尝试登录需要刷新过期时间。 使用lua脚本主要保证了对上述逻辑的原子性因为涉及获取key的值并判断然后将key的值1 或 删除key。 实现代码 Service类加载时加载lua脚本 private static final DefaultRedisScriptLong CHECK_LOGIN_SCRIPT;// 类加载时 加载lua脚本static {CHECK_LOGIN_SCRIPT new DefaultRedisScript();CHECK_LOGIN_SCRIPT.setLocation(new ClassPathResource(checkLogin.lua));CHECK_LOGIN_SCRIPT.setResultType(Long.class);}具体校验方法主要逻辑调用了lua脚本 private void checkLoginInfo(UserLoginContext userLoginContext) {String username userLoginContext.getUsername();String password userLoginContext.getPassword();//根据用户名查实体 从数据库RPanUser entity getRPanUserByUsername(username);if (Objects.isNull(entity)){throw new RPanBusinessException(用户名不存在);}String salt entity.getSalt(); //获取盐值String encPassword PasswordUtil.encryptPassword(salt, password) ; //将前端传 的密码加密String dbPassword entity.getPassword(); //获取数据库的密码// encPassword 表示前端传过来的 加密后的密码// dbPassword 表示数据库中的 加密后的密码// TODO 调用lua脚本判断 登录失败 登录成功 及锁定ipListString keys new ArrayList();String ipAddress HttpLogEntityBuilder.getIpAddress(userLoginContext.getRequest()); //获取请求ip// key设置为 ipusername进行锁定keys.add(UserConstants.CHECK_LOGIN_PREFIX ipAddress _ username);// 执行lua脚本Long result (Long)redisTemplate.execute(CHECK_LOGIN_SCRIPT, keys, encPassword, dbPassword, UserConstants.CHECK_LOGIN_THRESHOLD, UserConstants.CHECK_LOGIN_EXPIRE);if (result 0){throw new RPanBusinessException(用户名或密码不正确);}if (result -1){throw new RPanBusinessException(输入密码错误达到UserConstants.CHECK_LOGIN_THRESHOLD次请1分钟后尝试);}
// if (!Objects.equals(encPassword, dbPassword)) {
// throw new RPanBusinessException(密码信息不正确);
// }//填入实体信息userLoginContext.setEntity(entity);}lua脚本放在resources目录下 -- 判断用户登录的lua脚本local key1 KEYS[1]
local password1 ARGV[1]
local password2 ARGV[2]
-- 阈值
local threshold ARGV[3]
-- 过期时间
local expiretime ARGV[4]-- 判断key是否存在
local value redis.call(get, key1)-- 有key
if value thenif(value threshold) thenredis.call(expire, key1, expiretime) -- 刷新过期时间return -1 -- 输入密码错误达到threshold次请1分钟后尝试endif(password1 password2) then -- 校验正确删除key并返回1表示通过redis.call(del, key1)return 1elseredis.call(INCR, key1) -- key的值1redis.call(expire, key1, expiretime) -- 刷新过期时间return 0 -- 用户名或密码不正确end
end-- 没有key
if(password1 password2) thenreturn 1
elseredis.call(setex, key1, expiretime, 1) -- setex key [过期时间] 1return 0 -- 用户名或密码不正确
end