AOP+注解 解决重放攻击

防止重放攻击,简单来说就是防止短时间内多次恶意访问

方法:

    @ResponseBody
    @RequestMapping(value = "/saveOrUpdate", method = RequestMethod.POST)
    @RequestLimit
    public Object saveOrUpdate(MallStore store, HttpServletRequest request) {

注解:@RequestLimit 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {
    int time() default 60; //60s内

    int count() default 50; //访问超过50次后拒绝访问

    int waits() default 300; //超过后等待时间
}

AOP处理注解

@Aspect
@Component
@Order(6)
public class RequestLimitAspect {
    private static final String REQ_LIMIT = "req_limit_";

    /**
     * 定义拦截规则:拦截com.springboot.bcode.api包下面的所有类中,有@RequestLimit Annotation注解的方法
     * 。
     */
    @Around("execution(* com.xxx.xxxcontroller..*.*(..)) && @annotation(com.xxx.xxx.xxx.common.security.RequestLimit)")
    public Object method(ProceedingJoinPoint pjp) throws Throwable {

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod(); // 获取被拦截的方法
        RequestLimit limt = method.getAnnotation(RequestLimit.class);
        // No request for limt,continue processing request
        if (limt == null) {
            return pjp.proceed();
        }
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        int time = limt.time();
        int count = 3;
        int waits = limt.waits();

        String ip = RequestUtil.getIpAddr(request);
        String url = request.getRequestURI();
        String limitValue = "";
        StoreUpmsPrincipal principal1 = (StoreUpmsPrincipal) SecurityUtils.getSubject().getPrincipal();
        if (principal1 == null) {
            limitValue = principal1.getUserId().toString();
        }else {
            limitValue = ip;
        }

        // judge codition
        String key = requestLimitKey(url, limitValue);
        int nowCount = RedisUtil.get(key) == null ? 0 : Integer.valueOf(RedisUtil
                .get(key));

        if (nowCount == 0) {
            nowCount++;
            RedisUtil.set(key, String.valueOf(nowCount), time);
            return pjp.proceed();
        } else {
            nowCount++;
            RedisUtil.set(key, String.valueOf(nowCount), time);
            if (nowCount >= count) {
                System.out.println("用户IP[" + ip + "]访问地址[" + url + "]访问次数["
                        + nowCount + "]超过了限定的次数[" + count + "]限定时间[" + waits
                        + "秒]");
                RedisUtil.expire(key, waits);
                return returnLimit(request);
            }
        }

        return pjp.proceed();
    }

    /**
     * requestLimitKey: url_ip
     *
     * @param url
     * @param ip
     * @return
     */
    private static String requestLimitKey(String url, String ip) {

        StringBuilder sb = new StringBuilder();
        sb.append(REQ_LIMIT);
        sb.append(url);
        sb.append("_");
        sb.append(ip);
        return sb.toString();
    }

    /**
     * 返回拒绝信息
     *
     * @param request
     * @return
     * @throws IOException
     */
    private String returnLimit(HttpServletRequest request) throws IOException {

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getResponse();
        PrintWriter out = response.getWriter();
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        out.println("{\"code\": 50004,\"msg\":\"Service reject request!\"}");
        out.flush();
        out.close();
        return null;

    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值