美文网首页
利用Redis和自定义注解,限制登录次数

利用Redis和自定义注解,限制登录次数

作者: 茧铭 | 来源:发表于2019-12-27 14:09 被阅读0次

    使用自定义注解,并利用AOP切入注解的方法,判断当前登录人登录的次数,如果连续输入密码错误超过N次,则禁止该用户登录一段时间。
    代码如下
    首先是自定义注解

    
    /**
     * 限制登录次数
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Limit {
    
        /**
         * 名称,自定义使用位置,可用来区分
         */
        String name() default "";
    
        /**
         * 资源的key
         */
        String key() default "";
    
        /**
         * 前缀
         */
        String prefix() default "login_limit_";
    
        /**
         * 默认限制次数
         * 例:用在登录上即限制三次登录失败,就锁定账号一段时间
         */
        int count() default 3;
    
        /**
         * 默认限制时间,半个小时之内不能解除封印
         */
        int period() default 1800;
    
        /**
         * 限制类型
         */
        SysEnum.LimitType limitType() default SysEnum.LimitType.IP;
    }
    

    然后是具体的AOP逻辑

    
    /**
     * <p>
     * @description: 注解Limit的限制
     * </p>
     * @author: ZengGuangfu
     */
    
    @Slf4j
    @Aspect
    @Component
    public class LimitHandler {
    
        @Autowired
        RedisAuxiliary redisAuxiliary;
    
        @Pointcut("@annotation(com.emperor.go.config.annocation.Limit)")
        public void cut(){ }
    
        @Around("cut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            Object[] args = point.getArgs();
            Limit limit = methodSignature.getMethod().getAnnotation(Limit.class);
    
            Object result = null;
            //获取request
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (Objects.nonNull(limit)){
                // 获取参数
                String key = limit.key();
                String name = limit.name();
                String prefix = limit.prefix();
                int period = limit.period();
                int count = limit.count();
                SysEnum.LimitType limitType = limit.limitType();
    
                StringBuffer redisKey = new StringBuffer("prefix_");
                LoginVO lv = null;
                if (args != null && args.length > 0 && args[0] instanceof LoginVO){
                    lv = (LoginVO) args[0];
                }
                switch (limitType){
                    case IP:
                        redisKey.append(IPUtil.getIpAddr(request) + ":");
                        break;
                    case SPECIAL:
                        if (Objects.nonNull(lv)){
                            redisKey.append(key).append("_" + lv.getLoginName() + ":");
                        }
                        break;
                }
                String currentKey = redisKey.toString();
    
                /**
                 * 逻辑更改:
                 * 1.先查询redis有没有该记录,如果有,且数字大于 count 限制,即不能再登录
                 * 2.根据结果判断,如果登录成功,则清除缓存限制信息。如果失败了,则数字加一
                 */
                try{
                    int anInt = 0;
                    Long number = redisAuxiliary.getLong(currentKey);
                    if (Objects.nonNull(number)){
                        anInt = number.intValue();
                    }
                    if (anInt > count){
                        throw new GlobalException(CodeMsg.LOGIN_TOO_MUCH);
                    }
    
                    result = point.proceed();
                    if (Objects.nonNull(result) && result instanceof String){
                        if (result.equals("redirect:/main.html")){
                            redisAuxiliary.delete(currentKey);
                        }else if (result.equals("login")){
                            redisAuxiliary.incrByExpireTime(currentKey, 1800);
                        }
                    }
                }catch (NumberFormatException e){
                    throw new GlobalException(CodeMsg.RUNTIME_ERROR.fillMsg("Limit AOP 数字转换异常,可能是缓存存储数据不是数字"));
                }catch (GlobalException e){
                    throw e;
                }catch (Exception e){
                    throw e;
                }
            }
            return result;
        }
    }
    

    仅供参考

    相关文章

      网友评论

          本文标题:利用Redis和自定义注解,限制登录次数

          本文链接:https://www.haomeiwen.com/subject/xxqfgctx.html