SpringBoot實(shí)現(xiàn)接口防刷的兩種方法
什么是接口防刷
接口被刷指的是同一接口被頻繁調(diào)用,可能是由于以下原因?qū)е拢?/p>
- 惡意攻擊: 攻擊者利用自動(dòng)化腳本或工具對(duì)接口進(jìn)行大量請(qǐng)求,以消耗系統(tǒng)資源、拖慢系統(tǒng)響應(yīng)速度或達(dá)到其他惡意目的。
- 誤操作或程序錯(cuò)誤: 某些情況下,程序錯(cuò)誤或誤操作可能導(dǎo)致接口被重復(fù)調(diào)用,例如循環(huán)調(diào)用或者定時(shí)任務(wù)配置錯(cuò)誤。
常見(jiàn)的接口防刷策略
請(qǐng)求頻率限制:限制單個(gè)用戶或IP地址在一定時(shí)間內(nèi)能夠發(fā)送請(qǐng)求的次數(shù),防止用戶過(guò)度頻繁地發(fā)送請(qǐng)求。
驗(yàn)證碼驗(yàn)證:要求用戶在發(fā)送請(qǐng)求之前先進(jìn)行驗(yàn)證碼驗(yàn)證,從而確保該請(qǐng)求是來(lái)自真實(shí)用戶而不是機(jī)器人。
用戶身份認(rèn)證:要求用戶在發(fā)送請(qǐng)求之前先進(jìn)行身份認(rèn)證,例如使用用戶名和密碼進(jìn)行登錄或使用API密鑰進(jìn)行身份驗(yàn)證,從而確保只有合法的用戶可以發(fā)送請(qǐng)求。
動(dòng)態(tài)令牌:為每個(gè)請(qǐng)求生成一個(gè)動(dòng)態(tài)令牌,要求客戶端在請(qǐng)求中附帶該令牌,服務(wù)器端根據(jù)令牌來(lái)驗(yàn)證請(qǐng)求的合法性。
異常行為檢測(cè):通過(guò)監(jiān)控用戶的行為和請(qǐng)求模式,檢測(cè)異常的請(qǐng)求行為,例如短時(shí)間內(nèi)發(fā)送大量請(qǐng)求或者發(fā)送重復(fù)請(qǐng)求等,從而識(shí)別和阻止惡意用戶或機(jī)器人。
Redis 實(shí)現(xiàn)接口防刷
Redis是一種高性能的鍵值存儲(chǔ)系統(tǒng),常用于緩存和分布式鎖等場(chǎng)景。利用Redis可以有效地實(shí)現(xiàn)接口防刷功能:
- 計(jì)數(shù)器: 利用Redis的計(jì)數(shù)器功能,每次接口被調(diào)用時(shí)增加計(jì)數(shù)器的值,設(shè)定一個(gè)時(shí)間窗口內(nèi)的最大調(diào)用次數(shù),超過(guò)該次數(shù)則拒絕請(qǐng)求。
- 分布式鎖: 利用Redis的分布式鎖功能,確保同一時(shí)間只有一個(gè)請(qǐng)求能夠增加計(jì)數(shù)器的值,防止并發(fā)問(wèn)題導(dǎo)致計(jì)數(shù)器失效。
代碼示例
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; @Component public class RateLimitInterceptor extends HandlerInterceptorAdapter { @Resource private RedisTemplate<String, String> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String ipAddress = request.getRemoteAddr(); String key = "rate_limit:" + ipAddress; long count = redisTemplate.opsForValue().increment(key, 1); if (count == 1) { redisTemplate.expire(key, 1, TimeUnit.MINUTES); // 設(shè)置過(guò)期時(shí)間,防止數(shù)據(jù)永久存儲(chǔ) } if (count > 100) { // 設(shè)置閾值為每分鐘最多100次請(qǐng)求 response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); response.getWriter().write("請(qǐng)求過(guò)于頻繁,請(qǐng)稍后重試"); return false; } return true; } }
攔截器實(shí)現(xiàn)接口防刷
- 編寫(xiě)攔截器:創(chuàng)建一個(gè)實(shí)現(xiàn)HandlerInterceptor接口的攔截器類,重寫(xiě)preHandle方法,在該方法中進(jìn)行接口調(diào)用次數(shù)的檢查,如果超過(guò)閾值則攔截請(qǐng)求。
- 配置攔截器:在Spring Boot的配置類中通過(guò)addInterceptor方法將攔截器注冊(cè)到攔截器鏈中,配置攔截器的攔截路徑和排除路徑。
代碼示例
使用攔截器實(shí)現(xiàn)接口防刷
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class RateLimitInterceptor implements HandlerInterceptor { private static final int MAX_REQUESTS_PER_MINUTE = 100; private static final String RATE_LIMIT_KEY_PREFIX = "rate_limit:"; private final RedisTemplate<String, String> redisTemplate; public RateLimitInterceptor(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String ipAddress = request.getRemoteAddr(); String key = RATE_LIMIT_KEY_PREFIX + ipAddress; Long count = redisTemplate.opsForValue().increment(key, 1); if (count == 1) { redisTemplate.expire(key, 1, TimeUnit.MINUTES); } if (count > MAX_REQUESTS_PER_MINUTE) { response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); response.getWriter().write("請(qǐng)求過(guò)于頻繁,請(qǐng)稍后重試"); return false; } return true; } }
攔截器配置
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final RateLimitInterceptor rateLimitInterceptor; @Autowired public WebMvcConfig(RateLimitInterceptor rateLimitInterceptor) { this.rateLimitInterceptor = rateLimitInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(rateLimitInterceptor) .addPathPatterns("/**") .excludePathPatterns("/exclude/**"); // 可以排除一些不需要攔截的路徑 } }
總結(jié)
接口防刷是保障系統(tǒng)安全和穩(wěn)定性的重要手段,利用Redis和攔截器可以很好地實(shí)現(xiàn)接口防刷功能。通過(guò)合理設(shè)置閾值和時(shí)間窗口,以及監(jiān)控系統(tǒng)日志,可以及時(shí)發(fā)現(xiàn)異常情況并采取相應(yīng)措施,確保系統(tǒng)正常運(yùn)行
以上就是SpringBoot實(shí)現(xiàn)接口防刷的兩種方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot接口防刷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
玩轉(zhuǎn)spring boot 快速開(kāi)始(1)
玩轉(zhuǎn)spring boot,快速開(kāi)始spring boot學(xué)習(xí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Java中throw和throws異常處理完整例子說(shuō)明
這篇文章主要給大家介紹了關(guān)于Java中throw和throws異常處理的相關(guān)資料, throw關(guān)鍵字是用于在方法內(nèi)拋出異常,而throws關(guān)鍵字是在方法聲明中指定可能拋出的異常,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序介紹
這篇文章主要介紹了Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10IDEA創(chuàng)建父項(xiàng)目和子項(xiàng)目的實(shí)現(xiàn)步驟
本文主要介紹了IDEA創(chuàng)建父項(xiàng)目和子項(xiàng)目的實(shí)現(xiàn)步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07Java和Rust實(shí)現(xiàn)JSON序列化互轉(zhuǎn)的解決方案詳解
這篇文章主要為大家詳細(xì)介紹了Java和Rust實(shí)現(xiàn)JSON序列化互轉(zhuǎn)的解決方案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03Java如何使用ReentrantLock實(shí)現(xiàn)長(zhǎng)輪詢
這篇文章主要介紹了如何使用ReentrantLock實(shí)現(xiàn)長(zhǎng)輪詢,對(duì)ReentrantLock感興趣的同學(xué),可以參考下2021-04-04RabbitMQ通過(guò)延遲插件實(shí)現(xiàn)延遲消息
在RabbitMQ中,使用延遲消息插件比死信隊(duì)列更優(yōu)化的實(shí)現(xiàn)消息的延遲發(fā)送,本文介紹了延遲插件的下載、安裝、以及如何通過(guò)設(shè)置消息頭x-delay實(shí)現(xiàn)消息的延遲投遞,特別指出,使用延遲消息可能會(huì)損耗性能,適合短時(shí)間的延遲場(chǎng)景2024-10-10