龙空技术网

springboot AOP 接口调用错误次数限制自定义注解

睿智的搞笑图集 152

前言:

而今你们对“ajax中error参数”可能比较看重,大家都需要剖析一些“ajax中error参数”的相关内容。那么小编在网络上汇集了一些关于“ajax中error参数””的相关内容,希望各位老铁们能喜欢,大家一起来学习一下吧!

之前公司给政府做的一个项目被公安局的网络攻击人员给破解了,现在需要给登陆接口加上错误次数限制,于是使用了spring aop + 自定义注解来做

使用注解 @Around获取 ApiLimits 注解中的参数数组 ApiLimit[] , 支持多个纬度的限制调用方法之前判断是否已经被限制Object obj = proceed(joinPoint);给对应的key (使用apiLimit 中的参数拼接而成) 在redis 中 + 1

使用方式 :

    @ApiLimits({            @ApiLimit(limitTimeout = 1, limitCount = 5),            @ApiLimit(limitTimeout = 3, limitCount = 20),            @ApiLimit(limitTimeout = 1, limitCount = 50, unit = TimeUnit.HOURS, isRollIntoBlacklist = true)    })/****该使用方式表示,注解的接口,或方法 1分钟内 只能错误5次3分钟内 只能错误20次1个小时 只能错误50次,并且到达了这个纬度,将该IP放入黑名单(黑名单逻辑单独实现,会限制该IP访问系统中的任何接口)***/

具体实现 :

package com.shumei.edu.common.annotation;import java.lang.annotation.*;/** * * 接口调用错误限制 数组 * 注意如果有多个的话,应该将条件低的放在前面,这样如果碰到条件低的都不满足的话,会直接返回,不会执行下面的 */@Target({ ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ApiLimits{    ApiLimit[] value() ;}

package com.shumei.edu.common.annotation;import com.shumei.edu.common.enums.LimitType;import java.lang.annotation.*;import java.util.concurrent.TimeUnit;/** * 接口调用限制 */@Target({ ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ApiLimit{    // 限制类型, IP    LimitType[] limitType() default {LimitType.IP} ;    // 限制时间周期单位, 默认分钟    TimeUnit unit() default TimeUnit.MINUTES;    // 限制时间    int limitTimeout() default -1 ;    // 限制次数    int limitCount() default -1 ;    /**     * 是否滚进黑名单     * @return     */    boolean isRollIntoBlacklist() default false ;}

package com.shumei.edu.common.enums;/** */public enum LimitType{    /***/    IP ;}

package com.shumei.edu.framework.aspectj;import cn.hutool.core.util.StrUtil;import cn.hutool.json.JSONUtil;import com.alibaba.fastjson.JSON;import com.shumei.edu.common.annotation.ApiLimit;import com.shumei.edu.common.annotation.ApiLimits;import com.shumei.edu.common.enums.LimitType;import com.shumei.edu.common.exception.CustomException;import com.shumei.edu.common.utils.ServletUtils;import com.shumei.edu.common.utils.ip.IpUtils;import com.shumei.edu.common.web.domain.AjaxResult;import com.shumei.edu.framework.redis.redis.handle.RedisCacheEnum;import com.shumei.edu.framework.redis.redis.handle.RedisUtil;import com.shumei.edu.sys.blacklist.service.IBlackListService;import org.apache.commons.lang3.StringUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpMethod;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.HandlerMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.lang.reflect.Method;import java.util.Arrays;import java.util.Map;import java.util.Objects;/** * 接口调用错误限制 数组 * 注意如果有多个的话,应该将条件低的放在前面,这样如果碰到条件低的都不满足的话,会直接返回,不会执行下面的 */@Aspect@Componentpublic class ApiLimitsAspect {    private static final Logger log = LoggerFactory.getLogger(ApiLimitsAspect.class);    @Autowired    private RedisUtil redisUtil;    @Autowired    private IBlackListService blackListService;    // 配置织入点    @Pointcut("@annotation(com.shumei.edu.common.annotation.ApiLimits)")    public void logPointCut() { }    @Around(value = "logPointCut()")    public Object around(ProceedingJoinPoint pjp) throws Exception {        return handleLog(pjp);    }    protected Object handleLog(final ProceedingJoinPoint  joinPoint) throws Exception {        ApiLimit[] apiLimits = getAnnotationValues(joinPoint);        Object checkResult = checkLimitBefore(apiLimits);        if (checkResult instanceof AjaxResult){            return checkResult ;        }        Object obj = proceed(joinPoint);        if (!isRequestFail(obj)) {            return obj ;        }        checkResult = checkLimitAfter(apiLimits);        if (checkResult instanceof AjaxResult){            return checkResult ;        }        return obj ;    }    /**     * 判断是否请求失败     * @return     */    private boolean isRequestFail(Object obj) {        if (obj instanceof Throwable){            return true ;        }        Object jsonResult = Objects.isNull(obj) ? "" : obj;        boolean isRequestFail = true;        int code = 0;        if (jsonResult instanceof AjaxResult) {            code = Integer.valueOf(((AjaxResult) jsonResult).getCode());        } else {            boolean flag = JSONUtil.isJson(jsonResult.toString());            if (flag) {                code = JSONUtil.parseObj(jsonResult.toString()).getInt("code");            }        }        isRequestFail = code != 0;        return isRequestFail;    }    private Object proceed(ProceedingJoinPoint  joinPoint){        try {            return joinPoint.proceed();        } catch (CustomException e) {            return AjaxResult.error(e.getMessage());        } catch (Throwable throwable) {            throwable.printStackTrace();            return AjaxResult.error(throwable.getMessage());        }    }    public Object checkLimitAfter(ApiLimit[] apiLimits){        String fullKey = "";        for (int i = 0; i < apiLimits.length; i++) {            ApiLimit apiLimit = apiLimits[i];            LimitType[] limitTypes = apiLimit.limitType();            if (Arrays.asList(limitTypes).contains(LimitType.IP)) {                String ip = IpUtils.getIpAddr(ServletUtils.getRequest());                String uri = ServletUtils.getRequest().getRequestURI();                fullKey = "{}:{}:{}:{}:{}:{}" ;                fullKey = StrUtil.format(fullKey, LimitType.IP.name(), ip, apiLimit.unit().name(), apiLimit.limitTimeout(), apiLimit.limitCount(), uri);                Integer count = redisUtil.getObject(RedisCacheEnum.apiLimit, fullKey, Integer.class);                count = Objects.isNull(count) ? 0 : count;                if (count >= apiLimit.limitCount()) {                    if (apiLimit.isRollIntoBlacklist()) {                        boolean flag = blackListService.add(ip);                        log.info("加入黑名单 结果 {}, IP {}", flag, ip);                    }                    return AjaxResult.error("失败次数频繁,请稍后再试!");                } else {                    long failCount = redisUtil.incrRange(RedisCacheEnum.apiLimit, fullKey, apiLimit.unit(), apiLimit.limitTimeout());                    log.info("key: {} , 失败次数: {}, 最大失败次数:{}", fullKey, failCount + 1, apiLimit.limitCount());                }            }        }        return null ;    }    public Object checkLimitBefore(ApiLimit[] apiLimits){        String fullKey = "";        for (int i = 0; i < apiLimits.length; i++) {            ApiLimit apiLimit = apiLimits[i];            LimitType[] limitTypes = apiLimit.limitType();            if (Arrays.asList(limitTypes).contains(LimitType.IP)) {                String ip = IpUtils.getIpAddr(ServletUtils.getRequest());                String uri = ServletUtils.getRequest().getRequestURI();                fullKey = "{}:{}:{}:{}:{}:{}" ;                fullKey = StrUtil.format(fullKey, LimitType.IP.name(), ip, apiLimit.unit().name(), apiLimit.limitTimeout(), apiLimit.limitCount(), uri);                Integer count = redisUtil.getObject(RedisCacheEnum.apiLimit, fullKey, Integer.class);                count = Objects.isNull(count) ? 0 : count;                if (count >= apiLimit.limitCount()) {                    if (apiLimit.isRollIntoBlacklist()) {                        boolean flag = blackListService.add(ip);                        log.info("加入黑名单 结果 {}, IP {}", flag, ip);                    }                    return AjaxResult.error("失败次数频繁,请稍后再试!");                }            }        }        return null ;    }    /**     * 是否存在注解,如果存在就获取     */    private ApiLimits getAnnotation(JoinPoint joinPoint) throws Exception {        Signature signature = joinPoint.getSignature();        MethodSignature methodSignature = (MethodSignature) signature;        Method method = methodSignature.getMethod();        if (method != null) {            return method.getAnnotation(ApiLimits.class);        }        return null;    }    /**     * 是否存在注解,如果存在就获取     */    private ApiLimit[] getAnnotationValues(JoinPoint joinPoint) throws Exception {        ApiLimits apiLimits = getAnnotation(joinPoint);        if (apiLimits != null) {            return apiLimits.value();        }        return null;    }}

标签: #ajax中error参数