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

来源:互联网 发布:用windows 2000的电脑 编辑:程序博客网 时间:2024/05/20 07:19

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

看实现方式,基于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@Aspectpublic 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验证

@RestControllerpublic class IndexController {    @RequestLimit(count = 4)    @GetMapping("/index")    public Object index() {        return 1;    }}
启动工程,多次访问index看看效果即可。

原创粉丝点击