SpringBoot實(shí)現(xiàn)基于URL和IP的訪問頻率限制
1. 引言
在現(xiàn)代 Web 應(yīng)用中,接口被惡意刷新或暴力請(qǐng)求是一種常見的攻擊手段。為了保護(hù)系統(tǒng)資源,防止服務(wù)器過載或服務(wù)不可用,需要對(duì)接口的訪問頻率進(jìn)行限制。本文將介紹如何使用 Spring Boot 實(shí)現(xiàn)基于 URL 和 IP 的訪問頻率限制,具體步驟包括:
使用攔截器攔截請(qǐng)求:在每個(gè)請(qǐng)求到達(dá)控制器之前進(jìn)行攔截。
使用 Redis 存儲(chǔ)訪問記錄:利用 Redis 的高性能特性來存儲(chǔ)每個(gè) IP 對(duì)每個(gè) URL 的訪問次數(shù)。
檢測(cè)訪問頻率:判斷 IP 在一定時(shí)間內(nèi)對(duì)特定 URL 的訪問次數(shù)是否超過限制。
禁用惡意 IP:如果超過限制,則將 IP 列入黑名單,禁止其后續(xù)訪問。
2. 項(xiàng)目依賴
首先,在 pom.xml 中添加必要的依賴,包括 Spring Boot Web、Spring Boot Starter Data Redis 和 Lombok(用于簡(jiǎn)化代碼)。
<!-- Spring Boot Starter Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Lombok (可選,用于簡(jiǎn)化代碼) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
3. 配置 Redis
在 application.properties 中配置 Redis 連接信息:
server.port=8080 # Redis 配置 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.database=0 # 可選:設(shè)置密碼 # spring.redis.password=yourpassword
或在 application.yml 中配置Redis連接信息:
server:
port: 8080
spring:
application:
name: urlInterceptorDemo
data:
# redis 配置
redis:
# 地址
host: 127.0.0.1
# 端口,默認(rèn)為6379
port: 6379
# 數(shù)據(jù)庫索引
database: 0
# 密碼
password: "123456"
# 連接超時(shí)時(shí)間
timeout: 10s
4. 創(chuàng)建攔截器
創(chuàng)建一個(gè)攔截器 RateLimitInterceptor,用于攔截每個(gè)請(qǐng)求并執(zhí)行訪問頻率限制邏輯。
package com.yyqq.urlinterceptordemo.Interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.concurrent.TimeUnit;
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
@Autowired
public RedisTemplate redisTemplate;
// 訪問頻率限制:每個(gè) IP 每個(gè) URL 最多訪問 100 次 / 分鐘
private static final int MAX_REQUESTS = 10;
private static final int TIME_WINDOW = 60; // 秒
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = getClientIP(request);
String url = request.getRequestURI();
String key = "rate_limit:" + url + ":" + ip;
long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
// 設(shè)置鍵的過期時(shí)間為 TIME_WINDOW 秒
redisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);
}
if (count > MAX_REQUESTS) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("請(qǐng)求過于頻繁,請(qǐng)稍后再試。");
return false;
}
return true;
}
private String getClientIP(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}代碼說明
RedisTemplate:用于與 Redis 進(jìn)行交互。
MAX_REQUESTS 和 TIME_WINDOW:定義每個(gè) IP 在每個(gè) URL 上的最大訪問次數(shù)和時(shí)間窗口(60 秒)。
preHandle 方法:
獲取客戶端 IP 和請(qǐng)求的 URL。
構(gòu)建 Redis 鍵,例如 rate_limit:/api/data:192.168.1.1。
使用 increment 方法對(duì)鍵進(jìn)行遞增,并設(shè)置過期時(shí)間。
如果訪問次數(shù)超過 MAX_REQUESTS,則返回 403 狀態(tài)碼,并返回錯(cuò)誤信息。
getClientIP 方法:獲取客戶端的真實(shí) IP,處理代理和負(fù)載均衡的情況。
5. 注冊(cè)攔截器
創(chuàng)建一個(gè)配置類 WebConfig,將攔截器注冊(cè)到 Spring MVC 中。
package com.yyqq.urlinterceptordemo.config;
import com.yyqq.urlinterceptordemo.Interceptor.RateLimitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RateLimitInterceptor rateLimitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(rateLimitInterceptor)
.addPathPatterns("/**") // 攔截所有路徑
.excludePathPatterns("/error"); // 排除錯(cuò)誤路徑
}
}
代碼說明
- addInterceptors 方法:將自定義的攔截器添加到攔截器鏈中,并指定攔截的路徑模式。
- addPathPatterns("/")**:攔截所有路徑。
- excludePathPatterns(“/error”):排除錯(cuò)誤路徑,避免攔截器影響錯(cuò)誤處理。
6. 創(chuàng)建控制器
創(chuàng)建一個(gè)簡(jiǎn)單的控制器 DemoController,包含一個(gè)示例接口用于測(cè)試。
package com.yyqq.urlinterceptordemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class DemoController {
@GetMapping("/getData")
public String getData() {
return "這是數(shù)據(jù)接口,現(xiàn)在訪問正常!";
}
}
8. 測(cè)試
啟動(dòng) Spring Boot 應(yīng)用后,可以進(jìn)行以下測(cè)試:
1.正常訪問:
訪問 http://localhost:8080/test/getData,應(yīng)返回 “這是數(shù)據(jù)接口,現(xiàn)在訪問正常!”。
多次快速刷新,訪問次數(shù)達(dá)到 10 次后,應(yīng)返回 “請(qǐng)求過于頻繁,請(qǐng)稍后再試。”,并返回 403 狀態(tài)碼。

2.禁用 IP:
在達(dá)到限制后,等待一段時(shí)間(60 秒),再次訪問應(yīng)恢復(fù)正常。

9. 總結(jié)
通過結(jié)合使用 Spring Boot 攔截器和 Redis,本文實(shí)現(xiàn)了一種基于 URL 和 IP 的訪問頻率限制機(jī)制。這種機(jī)制能夠有效地防止接口被惡意刷新和暴力請(qǐng)求,保護(hù)系統(tǒng)資源,提高應(yīng)用的安全性和穩(wěn)定性。在實(shí)際應(yīng)用中,可以根據(jù)具體需求調(diào)整訪問頻率限制的參數(shù),如最大訪問次數(shù)和時(shí)間窗口。此外,還可以結(jié)合其他安全措施,如 IP 黑名單、驗(yàn)證碼等,進(jìn)一步增強(qiáng)系統(tǒng)的防護(hù)能力。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)基于URL和IP的訪問頻率限制的文章就介紹到這了,更多相關(guān)SpringBoot訪問頻率限制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring使用xml方式整合Druid數(shù)據(jù)源連接池
傳統(tǒng)的JDBC數(shù)據(jù)庫連接方式,每次連接都需加載Connection到內(nèi)存并驗(yàn)證,使用后再放回,從而重復(fù)利用數(shù)據(jù)庫連接資源,這不僅降低了系統(tǒng)資源消耗,還避免了頻繁連接導(dǎo)致的服務(wù)器崩潰和內(nèi)存泄漏風(fēng)險(xiǎn),數(shù)據(jù)庫連接池在初始化時(shí)創(chuàng)建并保持最小數(shù)量的數(shù)據(jù)庫連接2024-10-10
Java基礎(chǔ)知識(shí)精通塊作用域與條件及switch語句
塊(block,即復(fù)合語句)是指由若干條 Java 語句組成的語句,并由一對(duì)大括號(hào)括起來。塊確定了變量的作用域。一個(gè)塊可以嵌套在另一個(gè)塊中;條件語句、switch語句是我們常見會(huì)用到的結(jié)構(gòu),感興趣的朋友來看看吧2022-04-04
SpringBoot+SpringSecurity實(shí)現(xiàn)基于真實(shí)數(shù)據(jù)的授權(quán)認(rèn)證
Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架,Spring Security主要做兩個(gè)事情,認(rèn)證、授權(quán)。這篇文章主要介紹了SpringBoot+SpringSecurity實(shí)現(xiàn)基于真實(shí)數(shù)據(jù)的授權(quán)認(rèn)證,需要的朋友可以參考下2021-05-05
JavaWeb Refresh響應(yīng)頭代碼實(shí)例詳解
這篇文章主要介紹了JavaWeb Refresh響應(yīng)頭代碼實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
一文詳解如何在Java?Maven項(xiàng)目中使用JUnit?5進(jìn)行測(cè)試
這篇文章主要介紹了如何在Java?Maven項(xiàng)目中使用JUnit?5進(jìn)行測(cè)試的相關(guān)資料,JUnit5是一個(gè)流行的Java測(cè)試框架,它涵蓋了JUnit5的概述、環(huán)境配置、編寫測(cè)試用例、運(yùn)行測(cè)試、高級(jí)特性和最佳實(shí)踐,需要的朋友可以參考下2025-04-04
Java設(shè)計(jì)模式之策略模式原理與用法實(shí)例詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之策略模式原理與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java策略模式的概念、原理、定義及使用方法,并總結(jié)了相關(guān)的優(yōu)缺點(diǎn),具有一定參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04
使用jaxws建立webservice客戶端并實(shí)現(xiàn)soap消息的handler驗(yàn)證示例
這篇文章主要介紹了使用jaxws建立webservice客戶端并實(shí)現(xiàn)soap消息的handler驗(yàn)證示例,需要的朋友可以參考下2014-03-03
Java8(291)之后禁用了TLS1.1使JDBC無法用SSL連接SqlServer2008的解決方法
這篇文章主要介紹了Java8(291)之后禁用了TLS1.1使JDBC無法用SSL連接SqlServer2008的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03

