利用复述,实现登陆次数限制,注解+ aop,核心代码很简单。
比如希望达到的要求是这样:在1分钟内登陆异常次数达到5次,锁定该用户1 h
那么登陆请求的参数中,会有一个参数唯一标识一个用户,比如邮箱/手机号/用户名
用这个参数作为关键存入复述,对应的价值为登陆错误的次数、字符串类型,并设置过期时间为1分钟。当获取到的值=https://www.yisu.com/zixun/=?”,说明当前请求为第5次登陆异常,锁定。
所谓的锁定,就是将对应的值设置为某个标识符,比如“锁”,并设置过期时间为1 h
定义一个注解,用来标识需要登陆次数校验的方法
包io.github.xiaoyureed.redispractice.anno; 进口java.lang.annotation。*; @Documented @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) 公共@ interface RedisLimit {/* * *标识参数名,必须是请求参数中的一个 */字符串标识符();/* * *在多长时间内监控,如希望在60年代内尝试 *次数限制为5次,那么看=60;单位:年代 */长时间看();/* * *锁定时长,单位:s */长锁();/* * *错误的尝试次数 */int * (); }
编写切面,在目标方法前后进行校验,处理…
包io.github.xiaoyureed.redispractice.aop; @ component @Aspect//确保当前的建议是比ControllerAOP外//我们可以处理异常登录限制在这个aop的建议。//@Order (9) @Slf4j 公开课RedisLimitAOP { @ autowired 私人StringRedisTemplate StringRedisTemplate; @Around (“@annotation (io.github.xiaoyureed.redispractice.anno.RedisLimit)”) 公共对象handleLimit (ProceedingJoinPoint连接点){ MethodSignature MethodSignature=(MethodSignature) joinPoint.getSignature (); 最后的方法方法=methodSignature.getMethod (); 最后RedisLimit redisLimitAnno=method.getAnnotation (RedisLimit.class);//貌似可以直接在方法参数中注入todo 最终字符串标识符=redisLimitAnno.identifier (); 最后长看=redisLimitAnno.watch (); 最后一个int *=redisLimitAnno.times (); 最后长锁=redisLimitAnno.lock ();//最后ServletRequestAttributes att=(ServletRequestAttributes) RequestContextHolder.currentRequestAttributes ();//最后HttpServletRequest请求=att.getRequest ();//最后一个字符串identifierValue=https://www.yisu.com/zixun/request.getParameter(标识符); 字符串identifierValue=零; 尝试{ 最终对象参数=joinPoint.getArgs () [0]; 最后一场declaredField=arg.getClass () .getDeclaredField(标识符); declaredField.setAccessible(真正的); identifierValue=(字符串)declaredField.get (arg); }捕捉(NoSuchFieldException e) { log.error(“祝辞祝辞祝辞无效的标识符({}),找不到这个领域在请求参数”,标识符); }捕捉(IllegalAccessException e) { e.printStackTrace (); } 如果(StringUtils.isBlank (identifierValue)) { log.error(“祝辞祝辞祝辞RedisLimit的价值。标识符不能空白,无效的标识符:{}”,标识符); }//检查用户锁定 最后ValueOperations<字符串,String>ssop=stringRedisTemplate.opsForValue (); 最终字符串国旗=ssOps.get (identifierValue); 如果(国旗!=零,,“锁”.contentEquals(国旗)){ 最后BaseResp结果=new BaseResp (); 结果。setErrMsg(“用户锁定”); result.setCode (" 1 "); 返回新ResponseEntity<祝辞(因此,HttpStatus.OK); } ResponseEntity结果; 尝试{ 结果=(ResponseEntity) joinPoint.proceed (); }捕捉(Throwable e) { 结果=handleLoginException (e, identifierValue,手表,时间,锁); } 返回结果; } 私人ResponseEntity handleLoginException (Throwable e弦identifierValue,长期看,int,长锁){ 最后BaseResp结果=new BaseResp (); result.setCode (" 1 "); 如果(e instanceof LoginException) { log.info(“祝辞祝辞祝辞处理登录异常…”); 最后ValueOperations<字符串,String>ssop=stringRedisTemplate.opsForValue (); 布尔存在=stringRedisTemplate.hasKey (identifierValue);//键不存在,所以它是世界上第一个登录失败 如果存在(==null | | !存在){ ssop。集(identifierValue,“1”,看,TimeUnit.SECONDS); result.setErrMsg (e.getMessage ()); 返回新ResponseEntity<祝辞(因此,HttpStatus.OK); } 字符串数=ssOps.get (identifierValue);//已达到限制 如果(Integer.parseInt (count) + 1==*) { log.info(“祝辞祝辞祝辞({})已经达到限制和将被锁定为{}年代”,identifierValue,锁); ssop。集(identifierValue,“锁”锁,TimeUnit.SECONDS); 结果。setErrMsg(“用户锁定”); 返回新ResponseEntity复述,实现登陆次数限制的思路详解