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

基于SpringBoot實現(xiàn)IP黑白名單的詳細步驟

 更新時間:2024年01月25日 08:50:28   作者:進擊的阿晨  
IP黑白名單是網(wǎng)絡安全管理中常見的策略工具,用于控制網(wǎng)絡訪問權限,根據(jù)業(yè)務場景的不同,其應用范圍廣泛,比如比較容易被盜刷的短信接口、文件接口,都需要添加IP黑白名單加以限制,所以本文給大家介紹了基于SpringBoot實現(xiàn)IP黑白名單的詳細步驟,需要的朋友可以參考下

業(yè)務場景

IP黑白名單是網(wǎng)絡安全管理中常見的策略工具,用于控制網(wǎng)絡訪問權限,根據(jù)業(yè)務場景的不同,其應用范圍廣泛,以下是一些典型業(yè)務場景:

  • 服務器安全防護

    • 黑名單:可以用來阻止已知的惡意IP地址或曾經(jīng)嘗試攻擊系統(tǒng)的IP地址,防止這些來源對服務器進行未經(jīng)授權的訪問、掃描、攻擊等行為。
    • 白名單:僅允許特定IP或IP段訪問關鍵服務,比如數(shù)據(jù)庫服務器、內(nèi)部管理系統(tǒng)等,實現(xiàn)最小授權原則,降低被未知風險源入侵的可能性。
  • 網(wǎng)站安全防護

    • 黑名單:對于頻繁發(fā)起惡意請求、爬取數(shù)據(jù)、DDoS攻擊等活動的IP,將其加入黑名單以限制其對網(wǎng)站的訪問。
    • 白名單:如果只希望特定合作伙伴、內(nèi)部員工或特定區(qū)域用戶訪問網(wǎng)站內(nèi)容,則可通過白名單來限定合法訪問者的范圍。
  • API接口保護

    • 對于對外提供的API接口,通過設置IP黑白名單,確保只有經(jīng)過認證或信任的系統(tǒng)和客戶端才能調用接口。

比如比較容易被盜刷的短信接口、文件接口,都需要添加IP黑白名單加以限制。

核心實現(xiàn)

獲取客戶端IP地址

@UtilityClass
public class IpUtils {
    private final String UNKNOWN = "unknown";
    private final String X_FORWARDED_FOR = "X-Forwarded-For";
    private final String PROXY_CLIENT_IP = "Proxy-Client-IP";
    private final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
    private final Pattern COMMA_SEPARATED_VALUES_PATTERN = Pattern.compile("\s*,\s*");

    /**
     * 默認情況下內(nèi)網(wǎng)代理的子網(wǎng)可以是(后面有需要可以進行配置):
     * 1. 10/8
     * 2. 192.168/16
     * 3. 169.254/16
     * 4. 127/8
     * 5. 172.16/12
     * 6. ::1
     */
    private final Pattern INTERNAL_PROXIES = Pattern.compile(
            "10\.\d{1,3}\.\d{1,3}\.\d{1,3}|" +
                    "192\.168\.\d{1,3}\.\d{1,3}|" +
                    "169\.254\.\d{1,3}\.\d{1,3}|" +
                    "127\.\d{1,3}\.\d{1,3}\.\d{1,3}|" +
                    "172\.1[6-9]\.\d{1,3}\.\d{1,3}|" +
                    "172\.2[0-9]\.\d{1,3}\.\d{1,3}|" +
                    "172\.3[0-1]\.\d{1,3}\.\d{1,3}|" +
                    "0:0:0:0:0:0:0:1|::1"
    );

    /**
     * 獲取請求的IP
     *
     * @return 請求的IP
     */
    public String getIp() {
        var requestAttributes = RequestContextHolder.getRequestAttributes();
        if (Objects.isNull(requestAttributes)) {
            return null;
        }
        var request = ((ServletRequestAttributes) requestAttributes).getRequest();
        var ip = getRemoteIp(request);
        if (!StringUtils.hasLength(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(PROXY_CLIENT_IP);
        }
        if (!StringUtils.hasLength(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(WL_PROXY_CLIENT_IP);
        }
        if (!StringUtils.hasLength(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 獲取客戶端真實IP地址,防止使用X-Forwarded-For進行IP偽造攻擊,防御思路見類注釋
     *
     * @return 真實IP地址
     */
    private String getRemoteIp(HttpServletRequest request) {
        var remoteIp = request.getRemoteAddr();
        var isInternal = INTERNAL_PROXIES.matcher(remoteIp).matches();

        if (isInternal) {
            var concatRemoteIpHeaderValue = new StringBuilder();

            for (var e = request.getHeaders(X_FORWARDED_FOR); e.hasMoreElements(); ) {
                if (concatRemoteIpHeaderValue.length() > 0) {
                    concatRemoteIpHeaderValue.append(", ");
                }
                concatRemoteIpHeaderValue.append(e.nextElement());
            }

            var remoteIpHeaderValue = commaDelimitedListToArray(concatRemoteIpHeaderValue.toString());
            for (var i = remoteIpHeaderValue.length - 1; i >= 0; i--) {
                var currentRemoteIp = remoteIpHeaderValue[i];
                if (!INTERNAL_PROXIES.matcher(currentRemoteIp).matches()) {
                    return currentRemoteIp;
                }
            }
            return null;
        } else {
            return remoteIp;
        }
    }

    private String[] commaDelimitedListToArray(String commaDelimitedStrings) {
        return (commaDelimitedStrings == null || commaDelimitedStrings.isEmpty())
                ? new String[0]
                : COMMA_SEPARATED_VALUES_PATTERN.split(commaDelimitedStrings);
    }
}

獲取到客戶端IP后,我們只要比對客戶端IP是否在配置的白名單/黑名單中即可。 為了簡化使用,可以采用注解的方式進行攔截。

新增注解@IpCheck

/**
 * IP白名單校驗
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
@Inherited
public @interface IpCheck {

    /**
     * 白名單IP列表,支持${...}
     */
    @AliasFor("whiteList")
    String value() default "";

    /**
     * 白名單IP列表,支持${...}
     */
    @AliasFor("value")
    String whiteList() default "";

    /**
     * 黑名單IP列表,支持${...}
     */
    String blackList() default "";

}

新增IpCheckHandlerInterceptorImpl

我們實現(xiàn)HandlerInterceptor,在接口上進行攔截,如果不滿足配置的黑白名單,則拋出異常。

/**
 * @author <a href="mailto:gcwm99@gmail.com" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >gcdd1993</a>
 * Created by gcdd1993 on 2023/9/20
 */
@Component
public class IpCheckHandlerInterceptorImpl implements HandlerInterceptor, EmbeddedValueResolverAware {
    private StringValueResolver stringValueResolver;

    @Override
    public boolean preHandle(@NonNull HttpServletRequest request,
                             @NonNull HttpServletResponse response,
                             @NonNull Object handler) {
        // 檢查是否有IpWhitelistCheck注解,并且是否開啟IP白名單檢查
        if (!(handler instanceof HandlerMethod)) {
            return true;  // 如果沒有注解或者注解中關閉了IP白名單檢查,則繼續(xù)處理請求
        }
        var handlerMethod = (HandlerMethod) handler;
        var method = handlerMethod.getMethod();
        var annotation = AnnotationUtils.getAnnotation(method, IpCheck.class);
        if (annotation == null) {
            return true;
        }
        var clientIp = IpUtils.getIp();

        // 檢查客戶端IP是否在白名單中
        var whiteList = Stream.of(Optional.ofNullable(stringValueResolver.resolveStringValue(annotation.whiteList()))
                        .map(it -> it.split(","))
                        .orElse(new String[]{}))
                .filter(StringUtils::hasText)
                .map(String::trim)
                .collect(Collectors.toUnmodifiableSet());
        if (!whiteList.isEmpty() && whiteList.contains(clientIp)) {
            return true; // IP在白名單中,繼續(xù)處理請求
        }
        var blackList = Stream.of(Optional.ofNullable(stringValueResolver.resolveStringValue(annotation.blackList()))
                        .map(it -> it.split(","))
                        .orElse(new String[]{}))
                .filter(StringUtils::hasText)
                .map(String::trim)
                .collect(Collectors.toUnmodifiableSet());
        if (!blackList.isEmpty() && !blackList.contains(clientIp)) {
            return true; // IP不在黑名單中,繼續(xù)處理請求
        }
        // IP不在白名單中,可以返回錯誤響應或者拋出異常
        // 例如,返回一個 HTTP 403 錯誤
        throw new RuntimeException("Access denied, remote ip " + clientIp + " is not allowed.");
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.stringValueResolver = resolver;
    }
}

自動裝配

核心邏輯寫完了,該怎么使用呢?為了達到開箱即用的效果,我們可以接著新增自動裝配的代碼

新建IpCheckConfig

實現(xiàn)WebMvcConfigurer接口,添加接口攔截器

/**
 * @author <a href="mailto:gcwm99@gmail.com" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >gcdd1993</a>
 * Created by gcdd1993 on 2024/1/24
 */
public class IpCheckConfig implements WebMvcConfigurer {

    @Resource
    private IpCheckHandlerInterceptorImpl ipCheckHandlerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(ipCheckHandlerInterceptor);
    }

}

新建@EnableIpCheck

參考@EnableScheduling的實現(xiàn),自己實現(xiàn)一個@EnableIpCheck,該注解可以控制功能是否啟用

/**
 * @author <a href="mailto:gcwm99@gmail.com" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >gcdd1993</a>
 * Created by gcdd1993 on 2024/1/24
 */
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
@Documented
@ComponentScan("xxx.ip") // 這里是IpCheckConfig的包名
@Import(IpCheckConfig.class)
public @interface EnableIpCheck {
}

業(yè)務測試

簡單地用代碼來試驗下效果

新建SampleApplication

@SpringBootApplication
@EnableIpCheck
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

}

新建測試接口

@RestController
@RequestMapping("/sample/ip-checker")
public class IpCheckSample {

    @GetMapping("/white")
    @IpCheck(value = "0:0:0:0:0:0:0:1")
    String whiteList() {
        return "127.0.0.1";
    }

    @GetMapping("/black")
    @IpCheck(blackList = "0:0:0:0:0:0:0:1")
    String blackList() {
        return "127.0.0.1";
    }

    /**
     * 同時配置白名單和黑名單,要求IP既在白名單,并且不在黑名單,否則拋出異常
     */
    @GetMapping("/all")
    @IpCheck(value = "0:0:0:0:0:0:0:1", blackList = "0:0:0:0:0:0:0:1")
    String all() {
        return "127.0.0.1";
    }

    /**
     * 同時配置白名單和黑名單,要求IP既在白名單,并且不在黑名單,否則拋出異常
     * 支持解析Spring 配置文件
     */
    @GetMapping("/config")
    @IpCheck(value = "${digit.ip.check.white-list}", blackList = "${digit.ip.check.black-list}")
    String config() {
        return "127.0.0.1";
    }

    /**
     * 同時配置白名單和黑名單,要求IP既在白名單,并且不在黑名單,否則拋出異常
     * 支持解析Spring 配置文件
     */
    @GetMapping("/black-config")
    @IpCheck(blackList = "${digit.ip.check.black-list}")
    String blackConfig() {
        return "127.0.0.1";
    }

}

由于本機請求IP地址是0:0:0:0:0:0:0:1,所以這里使用0:0:0:0:0:0:0:1而不是127.0.0.1

訪問/sample/ip-checker/white

接口返回127.0.0.1

訪問/sample/ip-checker/black

java.lang.RuntimeException: Access denied, remote ip 0:0:0:0:0:0:0:1 is not allowed.

訪問/sample/ip-checker/all

接口返回127.0.0.1

  • 既配置白名單,也配置黑名單,需要既不在白名單,同時在黑名單里,才會攔截。

修改配置

digit:
  ip:
    check:
      white-list: 127.0.0.1, 192.168.1.1, 192.168.1.2
      black-list: 127.0.0.1, 192.168.1.1, 192.168.1.2,0:0:0:0:0:0:0:1

訪問/sample/ip-checker/black-config

java.lang.RuntimeException: Access denied, remote ip 0:0:0:0:0:0:0:1 is not allowed.

最后,可以結合配置中心,以便配置后立即生效。

以上就是基于SpringBoot實現(xiàn)IP黑白名單的詳細步驟的詳細內(nèi)容,更多關于SpringBoot IP黑白名單的資料請關注腳本之家其它相關文章!

相關文章

  • maven依賴的配置和排除依賴過程

    maven依賴的配置和排除依賴過程

    這篇文章主要介紹了maven依賴的配置和排除依賴過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • SpringBoot如何實現(xiàn)讀取.config文件

    SpringBoot如何實現(xiàn)讀取.config文件

    文章介紹如何在Java中讀取XML文件:通過創(chuàng)建XML數(shù)據(jù)源、定義POJO類(含父類Menudata和子類Menudatas)、編寫解析工具、實現(xiàn)Service層及Controller調用,最終使用Layui框架展示數(shù)據(jù),強調文件后綴轉換及層級結構處理
    2025-08-08
  • Swing圖形界面實現(xiàn)可動態(tài)刷新的驗證碼

    Swing圖形界面實現(xiàn)可動態(tài)刷新的驗證碼

    這篇文章主要為大家詳細介紹了Swing圖形界面實現(xiàn)可動態(tài)刷新的驗證碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Spring基于注解配置AOP詳解

    Spring基于注解配置AOP詳解

    這篇文章主要介紹了Spring基于注解配置AOP詳解,Spring 的 AOP 功能是基于 AspectJ 實現(xiàn)的,支持使用注解聲明式定義 AOP 切面,Spring 基于注解配置 AOP 需要啟用 AspectJ 自動代理功能,需要的朋友可以參考下
    2023-09-09
  • Java多個線程同時執(zhí)行的方法

    Java多個線程同時執(zhí)行的方法

    這篇文章主要介紹了Java多線程處理文件詳解與代碼示例,通過本文的介紹和代碼示例,我們了解了如何使用Java多線程來處理文件,使用多線程技術可以顯著提高文件處理的效率,特別是對于大量文件的處理任務,需要的朋友可以參考下
    2024-12-12
  • Sentinel的熔斷降級、資源規(guī)則詳解與實例

    Sentinel的熔斷降級、資源規(guī)則詳解與實例

    這篇文章主要介紹了Sentinel的熔斷降級、資源規(guī)則詳解與實例,Sentinel是阿里巴巴開源的一款流量控制和熔斷降級的框架,它主要用于保護分布式系統(tǒng)中的服務穩(wěn)定性,Sentinel通過對服務進行流量控制和熔斷降級,可以有效地保護系統(tǒng)的穩(wěn)定性,需要的朋友可以參考下
    2023-09-09
  • 舉例解析Java的圖像緩沖技術的使用

    舉例解析Java的圖像緩沖技術的使用

    這篇文章主要介紹了Java的圖像緩沖技術的使用,使用到了Java的awt.image包,需要的朋友可以參考下
    2015-10-10
  • Springboot項目中內(nèi)嵌sqlite數(shù)據(jù)庫的配置流程

    Springboot項目中內(nèi)嵌sqlite數(shù)據(jù)庫的配置流程

    這篇文章主要介紹了Springboot項目中內(nèi)嵌sqlite數(shù)據(jù)庫的配置流程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java如何通過線程解決生產(chǎn)者/消費者問題

    Java如何通過線程解決生產(chǎn)者/消費者問題

    這篇文章主要介紹了Java如何通過線程解決生產(chǎn)者/消費者問題,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-10-10
  • MyBatis配置與CRUD超詳細講解

    MyBatis配置與CRUD超詳細講解

    這篇文章主要介紹了MyBatis配置與CRUD,CRUD是指在做計算處理時的增加(Create)、讀取(Read)、更新(Update)和刪除(Delete)幾個單詞的首字母簡寫。CRUD主要被用在描述軟件系統(tǒng)中數(shù)據(jù)庫或者持久層的基本操作功能
    2023-02-02

最新評論

长泰县| 沿河| 涡阳县| 沙雅县| 望都县| 棋牌| 南靖县| 措勤县| 阳春市| 五寨县| 平利县| 银川市| 桃园市| 吉水县| 莆田市| 小金县| 榆林市| 上虞市| 盐源县| 河北省| 安仁县| 沁阳市| 瑞安市| 淳安县| 红河县| 遵化市| 台北市| 内丘县| 体育| 合川市| 荥经县| 宝山区| 庄浪县| 和平区| 安乡县| 虞城县| 大城县| 皋兰县| 金坛市| 中江县| 安岳县|