成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

接口被惡意狂刷,怎么辦?

開發(fā) 前端
判斷是否為相同請(qǐng)求,使用:URI+userId+日期。即Redis的key=URI+userId+yyyyMMdd,緩存有效期為一天。很多都在代碼里有注釋了,另外強(qiáng)調(diào)一下,不要吐槽代碼,僅僅是演示。

 [[415967]]

下面是原本面試現(xiàn)場(chǎng):

面試官:接口被惡意狂刷,怎么辦?

我:這個(gè)沒搞過(每天CRUD,真的沒搞過)

面試官:如果現(xiàn)在讓你來(lái)設(shè)計(jì),你會(huì)怎么設(shè)計(jì)?

我:巴拉巴拉...胡扯一通

面試官:(帶著不耐煩的表情)我們還是換個(gè)話題吧

.....

為了不讓大家也和我有同樣的遭遇,今天,咱們就用一個(gè)非常簡(jiǎn)單的方式實(shí)現(xiàn)防刷:

一個(gè)注解搞定防刷

技術(shù)點(diǎn)

涉及到的技術(shù)點(diǎn)有如下幾個(gè):

  • 自定義注解
  • 攔截器
  • Redis的基本操作
  • Spring Boot項(xiàng)目

其實(shí),非常簡(jiǎn)單,主要的還是看業(yè)務(wù)。

本文主要內(nèi)容:

自定義注解

自定義一注解AccessLimit。

  1. import java.lang.annotation.Retention; 
  2. import java.lang.annotation.Target; 
  3.   
  4. import static java.lang.annotation.ElementType.METHOD; 
  5. import static java.lang.annotation.RetentionPolicy.RUNTIME; 
  6.   
  7. @Retention(RUNTIME) 
  8. @Target(METHOD) 
  9. public @interface AccessLimit {  
  10.     //次數(shù)上限 
  11.     int maxCount(); 
  12.     //是否需要登錄 
  13.     boolean needLogin()default false

添加Redis配置項(xiàng)

在配置文件中,加入Redis配置;

  1. spring.redis.database=0 
  2. spring.redis.host=127.0.0.1 
  3. spring.redis.port=6379 
  4. spring.redis.jedis.pool.max-active=100 
  5. spring.redis.jedis.pool.max-idle=100 
  6. spring.redis.jedis.pool.min-idle=10 
  7. spring.redis.jedis.pool.max-wait=1000ms 

注意,把Redis的starter在pom中引入。

  1. <dependency> 
  2.     <groupId>org.springframework.boot</groupId> 
  3.     <artifactId>spring-boot-starter-data-redis</artifactId> 
  4.  </dependency> 

創(chuàng)建攔截器

創(chuàng)建攔截器,所有請(qǐng)求都進(jìn)行攔截,防刷的主要內(nèi)容全部在這里。

  1. // 一堆import 這里就不貼出來(lái)了,需要的自己導(dǎo)入 
  2. /** 
  3.  *  處理方法上 有 AccessLimitEnum 注解的方法 
  4.  * @author java后端技術(shù)全棧 
  5.  * @date 2021/8/6 15:42 
  6.  */ 
  7. @Component  
  8. public class FangshuaInterceptor extends HandlerInterceptorAdapter { 
  9.  
  10.     @Resource 
  11.     private RedisTemplate<String,Object> redisTemplate; 
  12.  
  13.     @Override 
  14.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
  15.  
  16.         System.out.println("----FangshuaInterceptor-----"); 
  17.         //判斷請(qǐng)求是否屬于方法的請(qǐng)求 
  18.         if (handler instanceof HandlerMethod) { 
  19.  
  20.             HandlerMethod hm = (HandlerMethod) handler; 
  21.  
  22.             //檢查方法上室友有AccessLimit注解 
  23.             AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class); 
  24.             if (accessLimit == null) { 
  25.                 return true
  26.             } 
  27.             //獲取注解中的參數(shù), 
  28.             int maxCount = accessLimit.maxCount(); 
  29.             boolean login = accessLimit.needLogin(); 
  30.             String key = request.getRequestURI(); 
  31.             //防刷=同一個(gè)請(qǐng)求路徑+同一個(gè)用戶+當(dāng)天 
  32.             //如果需要登錄 
  33.             if (login) { 
  34.                 //可以充session中獲取user相關(guān)信息 
  35.                 //這里的userId暫時(shí)寫死, 
  36.                 Long userId = 101L; 
  37.                 String currentDay = format(new Date(), "yyyyMMdd"); 
  38.                 key += currentDay + userId; 
  39.             }else
  40.                 //可以根據(jù)用戶使用的ip+日期進(jìn)行判斷 
  41.             } 
  42.  
  43.             //從redis中獲取用戶訪問的次數(shù) 
  44.             Object countCache = redisTemplate.opsForValue().get(key); 
  45.             if (countCache == null) { 
  46.                 //第一次訪問,有效期為一天 
  47.                 //時(shí)間單位自行定義 
  48.                 redisTemplate.opsForValue().set(key,1,86400, TimeUnit.SECONDS); 
  49.             } else
  50.                 Integer count = (Integer)countCache; 
  51.                 if (count < maxCount) { 
  52.                     //加1 
  53.                     count++; 
  54.                     //也可以使用increment(key)方法 
  55.                     redisTemplate.opsForValue().set(key,count); 
  56.                 } else { 
  57.                     //超出訪問次數(shù) 
  58.                     render(response, "訪問次數(shù)已達(dá)上限!"); 
  59.                     return false
  60.                 } 
  61.             } 
  62.         } 
  63.         return true
  64.     } 
  65.     //僅僅是為了演示哈 
  66.     private void render(HttpServletResponse response, String msg) throws Exception { 
  67.         response.setContentType("application/json;charset=UTF-8"); 
  68.         OutputStream out = response.getOutputStream(); 
  69.         out.write(msg.getBytes("UTF-8")); 
  70.         out.flush(); 
  71.         out.close(); 
  72.     } 
  73.     //日期格式 
  74.     public static String format(Date date, String formatString) { 
  75.         if (formatString == null) { 
  76.             formatString = DATE_TIME_FORMAT; 
  77.         } 
  78.         DateFormat dd = new SimpleDateFormat(formatString); 
  79.         return dd.format(date); 
  80.     } 

注意

判斷是否為相同請(qǐng)求,使用:URI+userId+日期。即Redis的key=URI+userId+yyyyMMdd,緩存有效期為一天。

很多都在代碼里有注釋了,另外強(qiáng)調(diào)一下,不要吐槽代碼,僅僅是演示。

注冊(cè)攔截器

盡管上面我們已經(jīng)自定義并實(shí)現(xiàn)好了攔截器,但還需要我們手動(dòng)注冊(cè)。

  1. import com.example.demo.ExceptionHander.FangshuaInterceptor; 
  2. import org.springframework.beans.factory.annotation.Autowired; 
  3. import org.springframework.context.annotation.Configuration; 
  4. import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 
  5. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 
  6.  
  7. @Configuration 
  8. public class WebConfig extends WebMvcConfigurerAdapter { 
  9.   
  10.     @Autowired 
  11.     private FangshuaInterceptor interceptor; 
  12.   
  13.   
  14.     @Override 
  15.     public void addInterceptors(InterceptorRegistry registry) { 
  16.         registry.addInterceptor(interceptor); 
  17.     } 

這樣我們的注解就正式注冊(cè)到攔截器鏈中了,后面項(xiàng)目中才會(huì)有效。

使用注解

前面的準(zhǔn)備都搞定了,現(xiàn)在來(lái)具體使用。

首先,我們創(chuàng)建一個(gè)簡(jiǎn)單的controller,然后,在方法上加上我們自定義的注解AccessLimit,就可以實(shí)現(xiàn)接口防刷了。

  1. import com.example.demo.result.Result; 
  2. import org.springframework.stereotype.Controller; 
  3. import org.springframework.web.bind.annotation.RequestMapping; 
  4. import org.springframework.web.bind.annotation.ResponseBody; 
  5.   
  6. @Controller 
  7. public class FangshuaController { 
  8.     //具體請(qǐng)求次數(shù)由具體業(yè)務(wù)決定,以及是否需要登錄 
  9.     @AccessLimit(maxCount=5, needLogin=true
  10.     @RequestMapping("/fangshua"
  11.     @ResponseBody 
  12.     public Object fangshua(){ 
  13.         return "請(qǐng)求成功"
  14.   
  15.     } 

測(cè)試,瀏覽器頁(yè)面上訪問:http://localhost:8080/fangshua

前面4次返回的是:請(qǐng)求成功

超過4次后變成:訪問次數(shù)已達(dá)上限!

一個(gè)注解就搞定了,是不是 so easy !!!

總結(jié)

關(guān)于接口防刷,如果在面試中被問到,至少還是能說(shuō)個(gè)123了。也建議大家手動(dòng)試試,自己搞出來(lái)了更帶勁兒。

 

責(zé)任編輯:武曉燕 來(lái)源: Java后端技術(shù)全棧
相關(guān)推薦

2024-08-06 08:08:14

2024-02-19 00:00:00

接口圖形驗(yàn)證碼

2025-05-12 09:30:51

2016-08-08 15:03:54

騰訊云電商騰訊云天御系統(tǒng)

2021-10-01 00:12:12

Redis分布式

2024-03-13 13:25:09

Redis分布式鎖

2011-06-30 17:58:30

網(wǎng)站被K

2020-07-10 08:46:26

HTTPS證書劫持網(wǎng)絡(luò)協(xié)議

2025-06-12 08:21:22

2015-03-31 15:33:55

2012-11-27 10:41:33

2021-04-13 10:41:25

Redis內(nèi)存數(shù)據(jù)庫(kù)

2018-11-27 09:28:41

API攻擊惡意

2011-06-27 15:42:23

降權(quán)SEO

2017-05-11 16:54:16

2017-12-08 11:14:21

2019-02-18 15:45:24

CPU頻率溫度

2015-03-24 16:58:18

iPhone6

2018-01-30 09:25:04

2022-09-05 09:02:01

服務(wù)器CPU服務(wù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩高清国产一区在线 | 日韩精品久久 | 亚洲国产精品视频一区 | 欧美在线视频二区 | 国产日韩精品一区 | 日本一区二区三区在线观看 | 麻豆久久精品 | 亚洲在线 | 日韩中文字幕第一页 | 亚洲一区视频在线 | 成人免费淫片aa视频免费 | 欧美黑人一区 | 一区二区三区免费 | 日韩中出 | 亚洲国产成人久久久 | 日本在线视频一区二区 | 99热欧美 | 国产高清免费视频 | 中文字幕不卡视频在线观看 | 一级久久久久久 | www.日韩高清| 国产福利在线播放 | 91.com在线观看| 九九久久在线看 | 成人性生交a做片 | 在线欧美一区 | 福利视频网站 | 91最新入口 | 亚洲精品一区二区三区在线 | 久久精品免费 | 亚洲精品国产电影 | 激情一区二区三区 | 久久com | 国产精品免费av | 狠狠爱免费视频 | 在线免费观看成年人视频 | 国产伦精品一区二区三区视频金莲 | 欧美日韩看片 | av影音资源 | 伊人网综合在线观看 | 国产精品久久久久无码av |