redis 实现登陆次数限制的思路详解
发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,title: redis-login-limitation利用 redis 实现登陆次数限制, 注解 + aop, 核心代码很简单.基本思路比如希望达到的要求是这样: 在 1min 内登陆异常次数达到
千家信息网最后更新 2026年11月03日redis 实现登陆次数限制的思路详解
title: redis-login-limitation
利用 redis 实现登陆次数限制, 注解 + aop, 核心代码很简单.
基本思路
比如希望达到的要求是这样: 在 1min 内登陆异常次数达到5次, 锁定该用户 1h
那么登陆请求的参数中, 会有一个参数唯一标识一个 user, 比如 邮箱/手机号/userName
用这个参数作为key存入redis, 对应的value为登陆错误的次数, string 类型, 并设置过期时间为 1min. 当获取到的 value == "4" , 说明当前请求为第 5 次登陆异常, 锁定.
所谓的锁定, 就是将对应的value设置为某个标识符, 比如"lock", 并设置过期时间为 1h
核心代码
定义一个注解, 用来标识需要登陆次数校验的方法
package io.github.xiaoyureed.redispractice.anno;import java.lang.annotation.*;@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RedisLimit { /** * 标识参数名, 必须是请求参数中的一个 */ String identifier(); /** * 在多长时间内监控, 如希望在 60s 内尝试 * 次数限制为5次, 那么 watch=60; unit: s */ long watch(); /** * 锁定时长, unit: s */ long lock(); /** * 错误的尝试次数 */ int times();}编写切面, 在目标方法前后进行校验, 处理...
package io.github.xiaoyureed.redispractice.aop;@Component@Aspect// Ensure that current advice is outer compared with ControllerAOP// so we can handling login limitation Exception in this aop advice.//@Order(9)@Slf4jpublic class RedisLimitAOP { @Autowired private StringRedisTemplate stringRedisTemplate; @Around("@annotation(io.github.xiaoyureed.redispractice.anno.RedisLimit)") public Object handleLimit(ProceedingJoinPoint joinPoint) { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); final Method method = methodSignature.getMethod(); final RedisLimit redisLimitAnno = method.getAnnotation(RedisLimit.class);// 貌似可以直接在方法参数中注入 todo final String identifier = redisLimitAnno.identifier(); final long watch = redisLimitAnno.watch(); final int times = redisLimitAnno.times(); final long lock = redisLimitAnno.lock(); // final ServletRequestAttributes att = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); // final HttpServletRequest request = att.getRequest(); // final String identifierValue = request.getParameter(identifier); String identifierValue = null; try { final Object arg = joinPoint.getArgs()[0]; final Field declaredField = arg.getClass().getDeclaredField(identifier); declaredField.setAccessible(true); identifierValue = (String) declaredField.get(arg); } catch (NoSuchFieldException e) { log.error(">>> invalid identifier [{}], cannot find this field in request params", identifier); } catch (IllegalAccessException e) { e.printStackTrace(); } if (StringUtils.isBlank(identifierValue)) { log.error(">>> the value of RedisLimit.identifier cannot be blank, invalid identifier: {}", identifier); } // check User locked final ValueOperations ssOps = stringRedisTemplate.opsForValue(); final String flag = ssOps.get(identifierValue); if (flag != null && "lock".contentEquals(flag)) { final BaseResp result = new BaseResp(); result.setErrMsg("user locked"); result.setCode("1"); return new ResponseEntity<>(result, HttpStatus.OK); } ResponseEntity result; try { result = (ResponseEntity) joinPoint.proceed(); } catch (Throwable e) { result = handleLoginException(e, identifierValue, watch, times, lock); } return result; } private ResponseEntity handleLoginException(Throwable e, String identifierValue, long watch, int times, long lock) { final BaseResp result = new BaseResp(); result.setCode("1"); if (e instanceof LoginException) { log.info(">>> handle login exception..."); final ValueOperations ssOps = stringRedisTemplate.opsForValue(); Boolean exist = stringRedisTemplate.hasKey(identifierValue); // key doesn't exist, so it is the first login failure if (exist == null || !exist) { ssOps.set(identifierValue, "1", watch, TimeUnit.SECONDS); result.setErrMsg(e.getMessage()); return new ResponseEntity<>(result, HttpStatus.OK); } String count = ssOps.get(identifierValue); // has been reached the limitation if (Integer.parseInt(count) + 1 == times) { log.info(">>> [{}] has been reached the limitation and will be locked for {}s", identifierValue, lock); ssOps.set(identifierValue, "lock", lock, TimeUnit.SECONDS); result.setErrMsg("user locked"); return new ResponseEntity<>(result, HttpStatus.OK); } ssOps.increment(identifierValue); result.setErrMsg(e.getMessage() + "; you have try " + ssOps.get(identifierValue) + "times."); } log.error(">>> RedisLimitAOP cannot handle {}", e.getClass().getName()); return new ResponseEntity<>(result, HttpStatus.OK); }} 这样使用:
package io.github.xiaoyureed.redispractice.web;@RestControllerpublic class SessionResources { @Autowired private SessionService sessionService; /** * 1 min 之内尝试超过5次, 锁定 user 1h */ @RedisLimit(identifier = "name", watch = 30, times = 5, lock = 10) @RequestMapping(value = "/session", method = RequestMethod.POST) public ResponseEntity login(@Validated @RequestBody LoginReq req) { return new ResponseEntity<>(sessionService.login(req), HttpStatus.OK); }} references
https://github.com/xiaoyureed/redis-login-limitation
总结
以上所述是小编给大家介绍的redis 实现登陆次数限制的思路详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
次数
登陆
参数
标识
限制
方法
时间
尝试
思路
代码
核心
注解
错误
帮助
出处
切面
就是
手机
手机号
时长
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
云南咖啡
互联网科技股
互联网科技图片
金融科技创新监管互联网金融
期待互联网科技
碳银互联网科技
深圳齐家互联网科技
互联网科技的未来发展
互联网科技论坛
卓越科技互联网 招聘
互联网科技公司招聘
济南华为互联网科技产业总部基地
河南猎农互联网科技有限公司
黑科技闪耀互联网之光
互联网科技和信息
高科技互联网发展前景如何
九思连强互联网电子科技有限公司
湖北辰鑫科技互联网
互联网时代高科技布局
杭州融税互联网科技有限公司
互联网与科技
广州为想互联网科技有限公司
互联网和科技创新
有马互联网科技
杭州互联网科技公司
苏州互联网科技贷款公司
互联网对科技的发展
花神(南京)互联网科技有限公司
黑云互联网科技有限公司
广州互联网高科技取餐柜