文档章节

如何限制用户在某一时间段多次访问接口

风间影月
 风间影月
发布于 2017/04/20 11:12
字数 801
阅读 16
收藏 0

要知道,如今很多平台的接口都是可以同时被门户网站,手机端,移动浏览器访问,因为接口是通用的,而为了安全起见,有些接口都会设置一个门槛,那就是限制访问次数,也就是在某一时间段内不能过多的访问,比如登录次数限制,在一些金融理财或者银行的接口上比较常见,另外一些与用户信息有关的接口都会有一个限制门槛

那么这个限制门槛怎么来做呢,其实有很多种方法,主流的做法可以用拦截器或者注解,那么今天咱们用注解来实现

首先需要定义一个注解,如下:

/**
 * 
 * @Title: LimitIPRequest.java
 * @Package com.agood.bejavagod.component
 * @Description: 限制某个IP在某个时间段内请求某个方法的次数
 * Copyright: Copyright (c) 2016
 * Company:Nathan.Lee.Salvatore
 * 
 * @author leechenxiang
 * @date 2016年12月14日 下午8:16:49
 * @version V1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)        // 设置顺序为最高优先级
public @interface LimitIPRequest {
    
    /**
     * 
     * @Description: 限制某时间段内可以访问的次数,默认设置100
     * @return
     * 
     * @author leechenxiang
     * @date 2016年12月14日 下午8:22:29
     */
    int limitCounts() default 100;

    /**
     * 
     * @Description: 限制访问的某一个时间段,单位为秒,默认值1分钟即可
     * @return
     * 
     * @author leechenxiang
     * @date 2016年12月14日 下午8:21:59
     */
    int timeSecond() default 60;
    
}

然后再使用spring aop,拦截被你注解的那个controller的方法

@Aspect
@Component
public class LimitIPRequestDisplay {

    @Autowired
    private JedisClient jedis;
    
    @Pointcut("execution(* com.agood.bejavagod.controller.*.*(..)) && @annotation(com.agood.bejavagod.component.LimitIPRequest)")
    public void before(){
    }

    @Before("before()")
    public void requestLimit(JoinPoint joinPoint) throws LimitIPRequestException {
        try {
            // 获取HttpRequest
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            HttpServletResponse response = attributes.getResponse();
            
            // 判断request不能为空
            if (request == null) {
                throw new LimitIPRequestException("HttpServletRequest有误...");
            }
            
            LimitIPRequest limit = this.getAnnotation(joinPoint);
            if(limit == null) {  
                return;  
            }  
            
            String ip = request.getRemoteAddr();
            String uri = request.getRequestURI().toString();
            String redisKey = "limit-ip-request:" + uri + ":" + ip;
            // 设置在redis中的缓存,累加1
            long count = jedis.incr(redisKey);
            
            // 如果该key不存在,则从0开始计算,并且当count为1的时候,设置过期时间
            if (count == 1) {
                jedis.expire(redisKey, limit.timeSecond());
//                redisTemplate.expire(redisKey, limit.time(), TimeUnit.MILLISECONDS);
            }
            
            // 如果redis中的count大于限制的次数,则报错
            if (count > limit.limitCounts()) {
                // logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
                if (ShiroFilterUtils.isAjax(request)) {
                    HttpServletResponse httpServletResponse = WebUtils.toHttp(response);  
                    httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_LIMIT_IP_REQUEST);
                } else {
                    throw new LimitIPRequestException();
                }
            }
        } catch (LimitIPRequestException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 
     * @Description: 获得注解
     * @param joinPoint
     * @return
     * @throws Exception
     * 
     * @author leechenxiang
     * @date 2016年12月14日 下午9:55:32
     */
    private LimitIPRequest getAnnotation(JoinPoint joinPoint) throws Exception {  
        Signature signature = joinPoint.getSignature();  
        MethodSignature methodSignature = (MethodSignature) signature;  
        Method method = methodSignature.getMethod();  
  
        if (method != null) {  
            return method.getAnnotation(LimitIPRequest.class);  
        }  
        return null;  
    }  
}

这个类使用了redis缓存作为计数器,因为好用,当然你用静态的map也行,但是考虑的分布式集群的话一般还是建议使用redis比较好。

大致的流程就是要获取redis中的调用方法次数,使用incr函数,当key不存在的时候默认为0然后累加1,当累加1大于limit设置的限制次数时,则抛出异常,这个地方需要注意,如果是ajax调用的话需要判断是否ajax,然后再返回错误信息

查看redis中key的剩余时间:

好,那么按照如上方法就能实现对接口访问次数的限制

本文转载自:http://www.cnblogs.com/leechenxiang/p/6181449.html

风间影月
粉丝 4
博文 126
码字总数 252
作品 0
无锡
技术主管
私信 提问
Nginx中如何限制某个IP同一时间段的访问次数

如何设置能限制某个IP某一时间段的访问次数是一个让人头疼的问题,特别面对恶意的ddos*的时候。其中CC(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站方法,*者...

guojianrui
2018/06/26
0
0
nginx限制某个IP同一时间段的访问次数

如何设置能限制某个IP某一时间段的访问次数是一个让人头疼的问题,特别面对恶意的ddos攻击的时候。其中CC攻击(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站攻...

Jean
2013/11/30
264
1
nginx限制某个IP同一时间段的访问次数

如何设置能限制某个IP某一时间段的访问次数是一个让人头疼的问题,特别面对恶意的ddos攻击的时候。其中CC攻击(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站攻...

山哥
2013/04/27
347
0
老板让你抗住千万级流量,如何做架构设计?

随着互联网的发展,各项软件的客户量日益增多,当客户量达到一定峰值时,当数以万计的流量来临时,程序的顺利运行以及即时响应则显得尤为重要,就像双11那天的淘宝一样。那么,如何设计架构才...

技术小能手
2018/11/23
0
0
MSSQL性能调优,有什么好的办法?

现有数据库记录网站访问流量数据,查询起来较慢,有什么调优的建议? 字段中查询使用到的列有:URL,UrlReferrer,VisiteDate 查询某一时间段,某一个URL访问数据,怎样能快速查询出来呢?表数...

情傷
2012/09/11
157
1

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.7K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部