分享

使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的

 WindySky 2019-02-28

使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制。

看实现方式,基于springboot,aop,redis。

新建Springboot工程,引入redis,aop。

创建注解

package com.tianyalei.annotation;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import java.lang.annotation.*;

/**

 * Created by wuwf on 17/7/6.

 */

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@Documented

//最高优先级

@Order(Ordered.HIGHEST_PRECEDENCE)

public @interface RequestLimit {

    /**

     * 允许访问的次数

     */

    int count() default 5;

    /**

     * 时间段,多少时间段内运行访问count次

     */

    long time() default 60000;

}

Aspect切面处理逻辑

package com.tianyalei.aspect;

import com.tianyalei.annotation.RequestLimit;

import com.tianyalei.util.HttpRequestUtil;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Component;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import java.util.concurrent.TimeUnit;

/**

 * Created by wuwf on 17/7/6.

 */

@Component

@Aspect

public class RequestLimitAspect {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired

    private RedisTemplate<String, String> redisTemplate;

    @Before("execution(public * com.tianyalei.controller.*.*(..)) && @annotation(limit)")

    public void requestLimit(JoinPoint joinpoint, RequestLimit limit) {

        // 接收到请求,记录请求内容

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = attributes.getRequest();

        String ip = HttpRequestUtil.getIpAddr(request);

        String url = request.getRequestURL().toString();

        String key = "req_limit_".concat(url).concat(ip);

        //加1后看看值

        long count = redisTemplate.opsForValue().increment(key, 1);

        //刚创建

        if (count == 1) {

            //设置1分钟过期

            redisTemplate.expire(key, limit.time(), TimeUnit.MILLISECONDS);

        }

        if (count > limit.count()) {

            logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");

            throw new RuntimeException("超出访问次数限制");

        }

    }

}

获取IP的工具类

package com.tianyalei.util;

import javax.servlet.http.HttpServletRequest;

import java.net.InetAddress;

import java.net.UnknownHostException;

/**

 * Created by admin on 17/7/6.

 */

public class HttpRequestUtil {

    /**

     * 获取当前网络ip

     *

     * @param request

     * @return

     */

    public static String getIpAddr(HttpServletRequest request) {

        String ipAddress = request.getHeader("x-forwarded-for");

        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

            ipAddress = request.getHeader("Proxy-Client-IP");

        }

        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

            ipAddress = request.getHeader("WL-Proxy-Client-IP");

        }

        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

            ipAddress = request.getRemoteAddr();

            if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {

                //根据网卡取本机配置的IP

                InetAddress inet = null;

                try {

                    inet = InetAddress.getLocalHost();

                } catch (UnknownHostException e) {

                    e.printStackTrace();

                }

                ipAddress = inet.getHostAddress();

            }

        }

        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割

        if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15

            if (ipAddress.indexOf(",") > 0) {

                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));

            }

        }

        return ipAddress;

    }

}

通过Controller验证

@RestController

public class IndexController {

    @RequestLimit(count = 4)

    @GetMapping("/index")

    public Object index() {

        return 1;

    }

}

启动工程,多次访问index看看效果即可。

--------------------- 

作者:天涯泪小武 

来源:CSDN 

原文:https://blog.csdn.net/tianyaleixiaowu/article/details/74549145 

版权声明:本文为博主原创文章,转载请附上博文链接!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多