欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot接口服務(wù),防刷、防止請求攻擊,AOP實(shí)現(xiàn)方式

 更新時(shí)間:2024年11月22日 14:45:53   作者:十&年  
本文介紹了如何使用AOP防止Spring?Boot接口服務(wù)被網(wǎng)絡(luò)攻擊,通過在pom.xml中加入AOP依賴,創(chuàng)建自定義注解類和AOP切面,以及在業(yè)務(wù)類中使用這些注解,可以有效地對接口進(jìn)行保護(hù),測試表明,這種方法有效地防止了網(wǎng)絡(luò)攻擊

springboot接口服務(wù),防刷、防止請求攻擊,AOP實(shí)現(xiàn)

本文使用AOP的方式防止spring boot的接口服務(wù)被網(wǎng)絡(luò)攻擊

pom.xml 中加入 AOP 依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

AOP自定義注解類

package org.jeecg.common.aspect.annotation;

import java.lang.annotation.*;

/**
 * 用于防刷限流的注解
 *      默認(rèn)是5秒內(nèi)只能調(diào)用一次
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {

    /** 限流的key */
    String key() default "limit:";

    /** 周期,單位是秒 */
    int cycle() default 5;

    /** 請求次數(shù) */
    int count() default 1;

    /** 默認(rèn)提示信息 */
    String msg() default "請勿重復(fù)點(diǎn)擊";
}

AOP切面業(yè)務(wù)類

package org.jeecg.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.aspect.annotation.RateLimit;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
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.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 切面類:實(shí)現(xiàn)限流校驗(yàn)
 */
@Aspect
@Component
public class AccessLimitAspect {

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    /**
     * 這里我們使用注解的形式
     * 當(dāng)然,我們也可以通過切點(diǎn)表達(dá)式直接指定需要攔截的package,需要攔截的class 以及 method
     */
    @Pointcut("@annotation(org.jeecg.common.aspect.annotation.RateLimit)")
    public void limitPointCut() {
    }

    /**
     * 環(huán)繞通知
     */
    @Around("limitPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取被注解的方法
        MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) pjp;
        MethodSignature signature = (MethodSignature) mjp.getSignature();
        Method method = signature.getMethod();

        // 獲取方法上的注解
        RateLimit rateLimit = method.getAnnotation(RateLimit.class);
        if (rateLimit == null) {
            // 如果沒有注解,則繼續(xù)調(diào)用,不做任何處理
            return pjp.proceed();
        }
        /**
         * 代碼走到這里,說明有 RateLimit 注解,那么就需要做限流校驗(yàn)了
         *  1、這里可以使用Redis的API做計(jì)數(shù)校驗(yàn)
         *  2、這里也可以使用Lua腳本做計(jì)數(shù)校驗(yàn),都可以
         */
        //獲取request對象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 獲取請求IP地址
        String ip = getIpAddr(request);
        // 請求url路徑
        String uri = request.getRequestURI();
        //存到redis中的key
        String key = "RateLimit:" + ip + ":" + uri;
        // 緩存中存在key,在限定訪問周期內(nèi)已經(jīng)調(diào)用過當(dāng)前接口
        if (redisTemplate.hasKey(key)) {
            // 訪問次數(shù)自增1
            redisTemplate.opsForValue().increment(key, 1);
            // 超出訪問次數(shù)限制
            if (redisTemplate.opsForValue().get(key) > rateLimit.count()) {
                throw new RuntimeException(rateLimit.msg());
            }
            // 未超出訪問次數(shù)限制,不進(jìn)行任何操作,返回true
        } else {
            // 第一次設(shè)置數(shù)據(jù),過期時(shí)間為注解確定的訪問周期
            redisTemplate.opsForValue().set(key, 1, rateLimit.cycle(), TimeUnit.SECONDS);
        }
        return pjp.proceed();
    }

    //獲取請求的歸屬IP地址
    private String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            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();
            }
            // 對于通過多個(gè)代理的情況,第一個(gè)IP為客戶端真實(shí)IP,多個(gè)IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) {
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }
        return ipAddress;
    }
}

測試

package org.jeecg.modules.api.controller;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.RateLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 測試接口
 * @author wujiangbo
 * @date 2022-08-23 18:50
 */
@RestController
@RequestMapping("/test")
public class TestController {

    //4秒內(nèi)只能訪問2次
    @RateLimit(key= "testLimit", count = 2, cycle = 4, msg = "大哥、慢點(diǎn)刷請求!")
    @GetMapping("/test001")
    public Result<?> rate() {
        System.out.println("請求成功");
        return Result.OK("請求成功!");
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中常用的設(shè)計(jì)模式之模板模式詳解

    Java中常用的設(shè)計(jì)模式之模板模式詳解

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)學(xué)生成績管理系統(tǒng),使用數(shù)據(jù)庫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • java?Spring的啟動(dòng)原理詳解

    java?Spring的啟動(dòng)原理詳解

    大家好,本篇文章主要講的是java?Spring的啟動(dòng)原理詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • Jersey實(shí)現(xiàn)Restful服務(wù)(實(shí)例講解)

    Jersey實(shí)現(xiàn)Restful服務(wù)(實(shí)例講解)

    下面小編就為大家?guī)硪黄狫ersey實(shí)現(xiàn)Restful服務(wù)(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • request如何獲取body的json數(shù)據(jù)

    request如何獲取body的json數(shù)據(jù)

    這篇文章主要介紹了request如何獲取body的json數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法

    Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法

    這篇文章主要介紹了Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法,本文使用apache-commons-net工具包時(shí)遇到這個(gè)問題,解決方法很簡單,需要的朋友可以參考下
    2015-05-05
  • jboss配置方法簡明教程

    jboss配置方法簡明教程

    這篇文章主要介紹了jboss配置方法,較為簡明扼要的說明了jboss服務(wù)器所需要的JDK環(huán)境安裝設(shè)置以及jboss的安裝與下載,并分析了配置與使用中的常見問題,需要的朋友可以參考下
    2016-08-08
  • Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中

    Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中

    因?yàn)閳?zhí)行需要,需要把jar內(nèi)templates文件夾下的的文件夾及文件加壓到宿主機(jī)器的某個(gè)路徑下,以便執(zhí)行對應(yīng)的腳本文件,這篇文章主要介紹了Springboot jar運(yùn)行時(shí)如何將jar內(nèi)的文件拷貝到文件系統(tǒng)中,需要的朋友可以參考下
    2024-06-06
  • Java線程生命周期及轉(zhuǎn)換過程

    Java線程生命周期及轉(zhuǎn)換過程

    這篇文章主要介紹了Java線程生命周期及轉(zhuǎn)換過程,線程的生命周期指的是線程從創(chuàng)建到銷毀的整個(gè)過程初始狀態(tài)、可運(yùn)行狀態(tài)、運(yùn)行狀態(tài)、休眠狀態(tài)、終止?fàn)顟B(tài),更多詳細(xì)介紹,需要的小伙伴可以參考下面文章內(nèi)容
    2022-05-05
  • Java中初始化List集合的八種方式匯總

    Java中初始化List集合的八種方式匯總

    List?是?Java?開發(fā)中經(jīng)常會(huì)使用的集合,下面這篇文章主要給大家介紹了關(guān)于Java中初始化List集合的八種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • java中BCryptPasswordEncoder密碼的加密與驗(yàn)證方式

    java中BCryptPasswordEncoder密碼的加密與驗(yàn)證方式

    這篇文章主要介紹了java中BCryptPasswordEncoder密碼的加密與驗(yàn)證方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評論