最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

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.*;

/**
 * 用于防刷限流的注解
 *      默認是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;

    /** 默認提示信息 */
    String msg() default "請勿重復點擊";
}

AOP切面業(yè)務類

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;

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

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    /**
     * 這里我們使用注解的形式
     * 當然,我們也可以通過切點表達式直接指定需要攔截的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 注解,那么就需要做限流校驗了
         *  1、這里可以使用Redis的API做計數(shù)校驗
         *  2、這里也可以使用Lua腳本做計數(shù)校驗,都可以
         */
        //獲取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)用過當前接口
        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ù)限制,不進行任何操作,返回true
        } else {
            // 第一次設置數(shù)據(jù),過期時間為注解確定的訪問周期
            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();
            }
            // 對于通過多個代理的情況,第一個IP為客戶端真實IP,多個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 = "大哥、慢點刷請求!")
    @GetMapping("/test001")
    public Result<?> rate() {
        System.out.println("請求成功");
        return Result.OK("請求成功!");
    }
}

總結

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

相關文章

  • Springboot打成war包并在tomcat中運行的部署方法

    Springboot打成war包并在tomcat中運行的部署方法

    這篇文章主要介紹了Springboot打成war包并在tomcat中運行,在文中還給大家介紹了SpringBoot war包tomcat運行啟動報錯(Cannot determine embedded database driver class for database type NONE)的解決方法,需要的朋友可以參考下
    2018-01-01
  • SpringBoot利用Redis解決海量重復提交問題

    SpringBoot利用Redis解決海量重復提交問題

    本文主要介紹了SpringBoot利用Redis解決海量重復提交問題,介紹了三種常見的解決方案,包括使用Redis計數(shù)器,使用Redis分布式鎖和使用Redis發(fā)布/訂閱機制,感興趣的可以了解一下
    2024-03-03
  • SpringBoot中Get請求和POST請求接收參數(shù)示例詳解

    SpringBoot中Get請求和POST請求接收參數(shù)示例詳解

    文章詳細介紹了SpringBoot中Get請求和POST請求的參數(shù)接收方式,包括方法形參接收參數(shù)、實體類接收參數(shù)、HttpServletRequest接收參數(shù)、@PathVariable接收參數(shù)、數(shù)組參數(shù)接收、集合參數(shù)接收、Map接收參數(shù)以及通過@RequestBody接收JSON格式的參數(shù),感興趣的朋友一起看看吧
    2024-12-12
  • SpringBoot實現(xiàn)輕量級動態(tài)定時任務管控及組件化的操作步驟

    SpringBoot實現(xiàn)輕量級動態(tài)定時任務管控及組件化的操作步驟

    文章介紹了一種在SpringBoot中實現(xiàn)動態(tài)定時任務的解決方案,基于COLA架構理論,封裝到了組件層,該組件支持類級別和方法級別的定時任務注冊,并提供了易用性和擴展性,組件使用Maven形式引入,并且可以通過YAML配置文件進行設置,感興趣的朋友一起看看吧
    2024-11-11
  • CORS跨域問題常用解決方法代碼實例

    CORS跨域問題常用解決方法代碼實例

    這篇文章主要介紹了CORS跨域問題常用解決方法代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • java中List去除重復數(shù)據(jù)的5種方式總結

    java中List去除重復數(shù)據(jù)的5種方式總結

    這篇文章主要給大家總結介紹了關于java中List去除重復數(shù)據(jù)的5種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • IDEA多線程文件下載插件開發(fā)的步驟詳解

    IDEA多線程文件下載插件開發(fā)的步驟詳解

    這篇文章主要介紹了IDEA多線程文件下載插件開發(fā)的步驟詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Java中RocketMQ使用方法詳解

    Java中RocketMQ使用方法詳解

    這篇文章主要介紹了RocketMQ和Kafka在SpringBoot中的使用方法,以及如何保證消息隊列的順序性、可靠性以及冪等性,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-02-02
  • 基于SpringBoot和Vue3的博客平臺文章列表與分頁功能實現(xiàn)

    基于SpringBoot和Vue3的博客平臺文章列表與分頁功能實現(xiàn)

    在前面的教程中,我們已經(jīng)實現(xiàn)了基于Spring Boot和Vue3的發(fā)布、編輯、刪除文章功能。本教程將繼續(xù)引導您實現(xiàn)博客平臺的文章列表與分頁功能,需要的朋友可以參考閱讀
    2023-04-04
  • Springboot+ElementUi實現(xiàn)評論、回復、點贊功能

    Springboot+ElementUi實現(xiàn)評論、回復、點贊功能

    這篇文章主要介紹了通過Springboot ElementUi實現(xiàn)評論、回復、點贊功能。如果是自己評論的還可以刪除,刪除的規(guī)則是如果該評論下還有回復,也一并刪除。需要的可以參考一下
    2022-01-01

最新評論

太原市| 雅江县| 蒙山县| 青冈县| 汉沽区| 嵊州市| 宁远县| 彰化市| 东兰县| 永仁县| 江华| 安乡县| 监利县| 隆化县| 郯城县| 高平市| 赤壁市| 南通市| 重庆市| 台东县| 呼玛县| 将乐县| 隆子县| 桓台县| 延川县| 万安县| 长汀县| 兖州市| 三门峡市| 黔江区| 清水县| 玛纳斯县| 揭阳市| 徐水县| 太仆寺旗| 双峰县| 太保市| 杂多县| 乌拉特中旗| 沭阳县| 长沙市|