SpringBoot中IP白名單控制實現(xiàn)限制接口訪問
一、IP白名單控制概述
1.1 什么是IP白名單
IP白名單(IP Whitelist)是一種網(wǎng)絡(luò)安全機制,它通過預(yù)先定義一組被允許訪問系統(tǒng)資源的IP地址列表,實現(xiàn)對網(wǎng)絡(luò)請求來源的精確控制。只有來自白名單中IP地址的請求才會被系統(tǒng)接受和處理,其他所有來源的請求都將被拒絕。
在Spring Boot應(yīng)用中實現(xiàn)IP白名單控制具有以下核心價值:
- 增強安全性:有效防止未授權(quán)訪問,降低惡意攻擊風(fēng)險
- 訪問控制:精確管理可訪問系統(tǒng)的客戶端范圍
- 資源保護:避免非預(yù)期流量消耗服務(wù)器資源
- 合規(guī)要求:滿足某些行業(yè)對訪問控制的監(jiān)管要求
1.2 IP白名單 vs 黑名單
| 特性 | IP白名單 | IP黑名單 |
|---|---|---|
| 控制邏輯 | 默認拒絕,明確允許 | 默認允許,明確拒絕 |
| 安全性 | 更高,僅已知安全IP可訪問 | 較低,新型攻擊源可能不在名單中 |
| 維護成本 | 較高,需要持續(xù)更新合法IP | 較低,只需添加已知惡意IP |
| 適用場景 | 內(nèi)部系統(tǒng)、高安全要求接口 | 公開服務(wù)、需要阻止特定惡意源 |
| 誤殺可能性 | 可能誤拒絕合法但未登記的IP | 可能漏過未登記的惡意IP |
1.3 IP白名單的應(yīng)用場景
- 內(nèi)部管理系統(tǒng):限制只有公司內(nèi)網(wǎng)或VPN IP可以訪問
- 支付接口:確保只有支付網(wǎng)關(guān)的服務(wù)器IP可以調(diào)用
- 數(shù)據(jù)同步接口:僅允許合作伙伴的指定服務(wù)器IP訪問
- 管理后臺:防止未授權(quán)的管理員訪問
- 第三方服務(wù)集成:限定合作方的調(diào)用來源
二、Spring Boot中實現(xiàn)IP白名單的技術(shù)選型
2.1 實現(xiàn)方案對比
在 Spring Boot 中實現(xiàn) IP 白名單功能時,可以選擇多種技術(shù)方案。以下是常見的 技術(shù)選型 及其適用場景、優(yōu)缺點分析:
1. 自定義 Filter 實現(xiàn)
實現(xiàn)方式
- 通過實現(xiàn)
javax.servlet.Filter接口,在doFilter方法中檢查請求的 IP 是否在白名單中。 - 配合
@Component注解注冊為 Spring Bean,并配置攔截路徑。
優(yōu)點
- 簡單直接:無需依賴額外框架,代碼實現(xiàn)靈活。
- 低耦合:與 Spring Security 無關(guān),適合輕量級需求。
- 可擴展性強:支持動態(tài)更新白名單(如從數(shù)據(jù)庫加載)。
缺點
- 需要手動處理 IP 獲取邏輯:需注意代理服務(wù)器(如 Nginx)后的真實 IP 獲取。
- 缺乏安全框架集成:無法與 Spring Security 的權(quán)限控制無縫結(jié)合。
適用場景
- 簡單項目或?qū)Π踩蟛桓叩膱鼍啊?/li>
- 需要完全自定義邏輯(如動態(tài)加載白名單)。
2. Spring Security 集成
實現(xiàn)方式
- 使用 Spring Security 提供的
hasIpAddress方法,配置白名單。 - 對于多 IP 白名單,需結(jié)合自定義表達式或策略。
優(yōu)點
- 與安全框架無縫集成:可與其他安全規(guī)則(如角色權(quán)限)結(jié)合。
- 配置靈活:支持基于路徑的細粒度控制。
缺點
- 配置復(fù)雜度較高:需要編寫自定義表達式或策略類。
- 不支持通配符:直接配置時僅支持精確匹配。
適用場景
- 已使用 Spring Security 的項目。
- 需要將 IP 白名單與其他安全規(guī)則(如 JWT、OAuth)結(jié)合。
3. AOP(面向切面編程)
實現(xiàn)方式
- 使用
@Aspect定義切面,在方法執(zhí)行前檢查 IP 是否在白名單中。 - 適用于對特定方法或類的訪問控制。
優(yōu)點
- 細粒度控制:可針對具體方法或類實現(xiàn) IP 攔截。
- 解耦業(yè)務(wù)邏輯:安全邏輯與業(yè)務(wù)代碼分離。
缺點
- 性能開銷:AOP 會增加方法調(diào)用的額外開銷。
- IP 獲取復(fù)雜:需在切面中獲取
HttpServletRequest對象。
適用場景
- 需要對特定方法(如敏感接口)進行 IP 校驗。
- 與業(yè)務(wù)邏輯解耦需求較高的場景。
4. 動態(tài)白名單(結(jié)合數(shù)據(jù)庫)
實現(xiàn)方式
- 將白名單存儲在數(shù)據(jù)庫中,通過定時任務(wù)或緩存刷新機制動態(tài)加載。
- 可結(jié)合 Redis 緩存提高性能。
優(yōu)點
- 靈活性高:無需重啟服務(wù)即可更新白名單。
- 適合生產(chǎn)環(huán)境:支持動態(tài)管理 IP 列表。
缺點
- 實現(xiàn)復(fù)雜度較高:需處理數(shù)據(jù)庫連接、緩存更新等邏輯。
- 性能依賴數(shù)據(jù)庫:頻繁查詢數(shù)據(jù)庫可能影響性能。
適用場景
- 白名單需要頻繁更新的場景。
- 多租戶系統(tǒng)或需要動態(tài)權(quán)限管理的系統(tǒng)。
5. 使用 Linux 防火墻(iptables/nftables)
實現(xiàn)方式
- 通過 Linux 命令行配置防火墻規(guī)則,限制訪問 IP。
- 與 Spring Boot 無關(guān),屬于操作系統(tǒng)層面的控制。
優(yōu)點
- 高性能:由操作系統(tǒng)直接處理,無需應(yīng)用層邏輯。
- 簡單高效:適合服務(wù)器級別的全局控制。
缺點
- 不可動態(tài)更新:需手動執(zhí)行命令或腳本。
- 缺乏靈活性:無法針對具體接口或方法控制。
適用場景
- 服務(wù)器級別的全局訪問控制。
- 與 Spring Boot 應(yīng)用無關(guān)的基礎(chǔ)設(shè)施防護。
6. 基于Interceptor的IP白名單
優(yōu)點
- 與 Spring MVC 集成良好:由于攔截器是 Spring MVC 的一部分,因此它能夠很好地集成到現(xiàn)有的 Spring Boot 應(yīng)用程序中。
- 適用于控制器級別的過濾:對于那些希望基于控制器或 API 級別進行 IP 訪問控制的應(yīng)用來說,這是一個理想的選擇。
- 靈活性高:可以根據(jù)不同的 URL 模式應(yīng)用不同的攔截規(guī)則,使得可以在不同的場景下靈活運用。
缺點
- 不適合全局過濾:對于不在控制器中的資源(例如靜態(tài)資源),可能無法有效攔截。如果需要對整個應(yīng)用程序?qū)嵤?IP 白名單策略,則可能不是最佳選擇。
- 性能開銷:雖然攔截器的性能開銷相對較小,但在高并發(fā)情況下,仍然需要注意其對系統(tǒng)性能的影響。
適用場景
- 需要對特定控制器或 API 進行 IP 訪問控制的應(yīng)用:比如某些敏感的操作只能由特定的 IP 地址執(zhí)行,這時可以使用攔截器來限制訪問。
- 已構(gòu)建了復(fù)雜的 Spring MVC 應(yīng)用程序的項目:如果您的應(yīng)用程序已經(jīng)大量使用了 Spring MVC 的特性,那么使用攔截器將是一個自然且易于維護的選擇。
- 輕量級的 IP 白名單需求:當您只需要簡單的 IP 白名單功能而不希望引入如 Spring Security 等較重的安全框架時,攔截器提供了一個輕便的解決方案。
6. 技術(shù)選型對比表
| 技術(shù)方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| 自定義 Filter | 簡單直接,靈活性高 | 需手動處理 IP 獲取邏輯 | 輕量級項目或動態(tài)白名單需求 |
| Spring Security | 與安全框架集成,配置靈活 | 配置復(fù)雜,不支持通配符 | 已使用 Spring Security 的項目 |
| AOP | 細粒度控制,解耦業(yè)務(wù)邏輯 | 性能開銷,IP 獲取復(fù)雜 | 特定方法或類的訪問控制 |
| 動態(tài)白名單 | 靈活,適合生產(chǎn)環(huán)境 | 實現(xiàn)復(fù)雜,依賴數(shù)據(jù)庫性能 | 多租戶系統(tǒng)或動態(tài)管理需求 |
| 基于 Interceptor | 與 Spring MVC 集成良好,適用于控制器層面的過濾 | 不適合全局過濾,如靜態(tài)資源等 | 控制器級別的 IP 訪問控制 |
| Linux 防火墻 | 高性能,簡單高效 | 不可動態(tài)更新,缺乏靈活性 | 服務(wù)器級別全局控制 |
三、完整實現(xiàn)方案
3.1 自定義 Filter 實現(xiàn) IP 白名單
1.1 添加依賴
Spring Boot 默認支持 Servlet API,無需額外依賴。
1.2 創(chuàng)建配置文件
在 application.yml 中配置白名單:
ip: whitelist: "192.168.1.1, 192.168.1.2"
1.3 創(chuàng)建 Filter 類
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* 自定義 IP 白名單 Filter
* 作用:攔截請求,檢查客戶端 IP 是否在白名單中
*/
@Component
public class IpWhiteListFilter implements Filter {
@Value("${ip.whitelist}")
private String whitelistStr;
// 用于存儲白名單的 List
private List<String> whiteList;
/**
* 初始化白名單
*/
@Override
public void init(FilterConfig filterConfig) {
whiteList = Arrays.stream(whitelistStr.split(","))
.map(String::trim)
.collect(java.util.stream.Collectors.toList());
}
/**
* 處理請求
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String clientIP = getClientIP(httpRequest); // 獲取真實 IP
if (whiteList.contains(clientIP)) {
chain.doFilter(request, response); // IP 在白名單中,放行
} else {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "IP 未授權(quán)訪問");
}
}
/**
* 獲取客戶端真實 IP(支持代理服務(wù)器)
*/
private String getClientIP(HttpServletRequest request) {
// 從 X-Forwarded-For 頭獲取真實 IP
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr(); // 如果沒有代理,直接獲取遠程地址
}
return ip;
}
@Override
public void destroy() {
// 清理資源
}
}
1.4 注冊 Filter(可選)
如果未使用 @Component 注解,可通過配置類注冊:
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<IpWhiteListFilter> ipWhiteListFilter(IpWhiteListFilter filter) {
FilterRegistrationBean<IpWhiteListFilter> registration = new FilterRegistrationBean<>(filter);
registration.addUrlPatterns("/*"); // 攔截所有請求
return registration;
}
}
3.2 Spring Security 實現(xiàn) IP 白名單
2.1 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2 配置白名單
在 application.yml 中配置白名單:
ip: whitelist: "192.168.1.1, 192.168.1.2"
2.3 創(chuàng)建 Security 配置類
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import java.util.Arrays;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${ip.whitelist}")
private String[] whiteList;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**")
.access("hasIpAddress('192.168.1.1') or hasIpAddress('192.168.1.2')") // 支持多個 IP
.and()
.csrf().disable(); // 關(guān)閉 CSRF 保護
}
}
3.3 AOP 實現(xiàn) IP 白名單
3.1 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3.2 創(chuàng)建自定義注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義注解,標記需要 IP 白名單保護的方法
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IpWhiteList {
}
3.3 創(chuàng)建 AOP 切面類
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* AOP 切面類:檢查 IP 是否在白名單中
*/
@Aspect
@Component
public class IpWhiteListAspect {
@Value("${ip.whitelist}")
private String whitelistStr;
private List<String> whiteList;
public IpWhiteListAspect() {
// 初始化白名單
whiteList = Arrays.stream(whitelistStr.split(","))
.map(String::trim)
.collect(java.util.stream.Collectors.toList());
}
/**
* 切面邏輯:在方法執(zhí)行前檢查 IP
*/
@Around("@annotation(IpWhiteList)")
public Object checkIp(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String clientIP = getClientIP(request);
if (whiteList.contains(clientIP)) {
return joinPoint.proceed(); // IP 在白名單中,繼續(xù)執(zhí)行方法
} else {
throw new AccessDeniedException("IP 未授權(quán)訪問");
}
}
/**
* 獲取客戶端真實 IP(支持代理服務(wù)器)
*/
private String getClientIP(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
3.4 在方法上使用注解
@RestController
public class DemoController {
@IpWhiteList
@GetMapping("/api/test")
public String test() {
return "Access granted";
}
}
3.4 動態(tài)白名單(數(shù)據(jù)庫 + 緩存)
4.1 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
4.2 創(chuàng)建數(shù)據(jù)庫表
CREATE TABLE sys_ip_whitelist (
id INT PRIMARY KEY AUTO_INCREMENT,
ip VARCHAR(45) NOT NULL
);
4.3 創(chuàng)建實體類
import jakarta.persistence.*;
@Entity
@Table(name = "sys_ip_whitelist")
public class SysIpWhitelist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String ip;
// Getters and Setters
}
4.4 創(chuàng)建 Mapper 接口
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysIpWhitelistRepository extends JpaRepository<SysIpWhitelist, Long> {
SysIpWhitelist findByIp(String ip);
}
4.5 創(chuàng)建 Service 類
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class WhiteListService {
@Autowired
private SysIpWhitelistRepository repository;
// 使用 Redis 緩存白名單(示例代碼)
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String WHITE_LIST_KEY = "ip:white_list";
/**
* 檢查 IP 是否在白名單中(支持緩存)
*/
public boolean isWhiteListed(String ip) {
// 先查緩存
List<String> cachedList = (List<String>) redisTemplate.opsForValue().get(WHITE_LIST_KEY);
if (cachedList != null && cachedList.contains(ip)) {
return true;
}
// 再查數(shù)據(jù)庫
SysIpWhitelist entity = repository.findByIp(ip);
if (entity != null) {
// 更新緩存
List<String> list = repository.findAll().stream().map(SysIpWhitelist::getIp).collect(Collectors.toList());
redisTemplate.opsForValue().set(WHITE_LIST_KEY, list, 1, TimeUnit.MINUTES);
return true;
}
return false;
}
}
4.6 在 Filter 或 AOP 中調(diào)用 Service
@Autowired
private WhiteListService whiteListService;
// 在 doFilter 或 checkIp 方法中調(diào)用
if (!whiteListService.isWhiteListed(clientIP)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "IP 未授權(quán)訪問");
}
3.5 Linux 防火墻實現(xiàn) IP 白名單
5.1 安裝 iptables
sudo apt update sudo apt install iptables
5.2 配置白名單規(guī)則
# 允許白名單 IP sudo iptables -A INPUT -s 192.168.1.1 -j ACCEPT sudo iptables -A INPUT -s 192.168.1.2 -j ACCEPT # 拒絕其他所有 IP sudo iptables -A INPUT -j DROP
5.3 保存規(guī)則(可選)
# 安裝保存工具 sudo apt install iptables-persistent # 保存規(guī)則 sudo netfilter-persistent save
3.6 基于Interceptor的IP白名單
1. 項目初始化與依賴配置
首先創(chuàng)建一個標準的Spring Boot項目,添加必要依賴:
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok簡化代碼 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 配置處理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. IP白名單配置設(shè)計
創(chuàng)建配置類IpWhitelistProperties:
@ConfigurationProperties(prefix = "security.ip.whitelist")
@Data
public class IpWhitelistProperties {
/**
* 是否啟用IP白名單功能
*/
private boolean enabled = false;
/**
* 全局IP白名單列表
*/
private List<String> globalAllowedIps = new ArrayList<>();
/**
* 監(jiān)控模式:true-只記錄不攔截,false-實際攔截
*/
private boolean monitorMode = false;
/**
* 允許的IP段,支持CIDR表示法
*/
private List<String> allowedIpRanges = new ArrayList<>();
}
對應(yīng)的application.yml配置示例:
security:
ip:
whitelist:
enabled: true
global-allowed-ips:
- 192.168.1.100
- 172.16.0.50
allowed-ip-ranges:
- 10.0.0.0/8
- 192.168.0.0/16
monitor-mode: false
3. IP工具類實現(xiàn)
創(chuàng)建IpUtils工具類處理IP相關(guān)邏輯:
public class IpUtils {
private static final String UNKNOWN = "unknown";
private static final String LOCALHOST_IPV4 = "127.0.0.1";
private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
/**
* 獲取客戶端真實IP地址
*/
public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 處理多級代理情況
if (ip != null && ip.contains(",")) {
ip = ip.substring(0, ip.indexOf(",")).trim();
}
return LOCALHOST_IPV6.equals(ip) ? LOCALHOST_IPV4 : ip;
}
/**
* 檢查IP是否匹配CIDR表示法的IP段
*/
public static boolean isIpInRange(String ip, String cidr) {
// 實現(xiàn)細節(jié)...
}
/**
* 驗證IP地址格式
*/
public static boolean isValidIp(String ip) {
// 實現(xiàn)細節(jié)...
}
}
4. 自定義注解設(shè)計
創(chuàng)建@IpWhitelist注解支持方法級別的控制:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IpWhitelist {
/**
* 是否啟用IP白名單檢查
*/
boolean enabled() default true;
/**
* 特定于該接口的允許IP列表
*/
String[] allowedIps() default {};
/**
* 特定于該接口的允許IP段(CIDR)
*/
String[] allowedIpRanges() default {};
/**
* 拒絕時的錯誤消息
*/
String message() default "Access denied by IP whitelist";
}
5. 攔截器核心實現(xiàn)
創(chuàng)建IpWhitelistInterceptor攔截器:
@RequiredArgsConstructor
public class IpWhitelistInterceptor implements HandlerInterceptor {
private final IpWhitelistProperties properties;
private final ObjectMapper objectMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!properties.isEnabled()) {
return true;
}
// 處理HandlerMethod情況
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 檢查類和方法上的注解
IpWhitelist classAnnotation = handlerMethod.getBeanType().getAnnotation(IpWhitelist.class);
IpWhitelist methodAnnotation = method.getAnnotation(IpWhitelist.class);
// 如果都沒有注解,則跳過檢查
if (classAnnotation == null && methodAnnotation == null) {
return true;
}
// 合并注解配置
boolean enabled = methodAnnotation != null ? methodAnnotation.enabled() :
classAnnotation.enabled();
String[] allowedIps = methodAnnotation != null && methodAnnotation.allowedIps().length > 0 ?
methodAnnotation.allowedIps() :
classAnnotation != null ? classAnnotation.allowedIps() : new String[0];
String[] allowedIpRanges = methodAnnotation != null && methodAnnotation.allowedIpRanges().length > 0 ?
methodAnnotation.allowedIpRanges() :
classAnnotation != null ? classAnnotation.allowedIpRanges() : new String[0];
String message = methodAnnotation != null ? methodAnnotation.message() :
classAnnotation != null ? classAnnotation.message() : "Access denied by IP whitelist";
if (!enabled) {
return true;
}
String clientIp = IpUtils.getClientIp(request);
// 檢查全局白名單
boolean isAllowed = properties.getGlobalAllowedIps().contains(clientIp) ||
properties.getAllowedIpRanges().stream()
.anyMatch(range -> IpUtils.isIpInRange(clientIp, range));
// 檢查注解指定的白名單
if (!isAllowed) {
isAllowed = Arrays.stream(allowedIps).anyMatch(ip -> ip.equals(clientIp)) ||
Arrays.stream(allowedIpRanges)
.anyMatch(range -> IpUtils.isIpInRange(clientIp, range));
}
if (!isAllowed) {
if (properties.isMonitorMode()) {
log.warn("IP whitelist monitor mode triggered. Denied IP: {}", clientIp);
return true;
}
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.FORBIDDEN.value());
response.getWriter().write(objectMapper.writeValueAsString(
Map.of(
"code", 403,
"message", message,
"data", null
)
));
return false;
}
return true;
}
}
6. 攔截器注冊配置
創(chuàng)建Web配置類注冊攔截器:
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final IpWhitelistProperties ipWhitelistProperties;
private final ObjectMapper objectMapper;
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (ipWhitelistProperties.isEnabled()) {
registry.addInterceptor(new IpWhitelistInterceptor(ipWhitelistProperties, objectMapper))
.addPathPatterns("/**")
.order(Ordered.HIGHEST_PRECEDENCE); // 設(shè)置最高優(yōu)先級
}
}
}
7. 控制器示例
創(chuàng)建測試控制器驗證功能:
@RestController
@RequestMapping("/api")
public class TestController {
@GetMapping("/public")
public String publicApi() {
return "This is a public API";
}
@IpWhitelist
@GetMapping("/secure")
public String secureApi() {
return "This is a secure API with IP whitelist";
}
@IpWhitelist(
allowedIps = {"192.168.1.100", "172.16.0.50"},
allowedIpRanges = {"10.0.0.0/8"},
message = "Custom IP restriction"
)
@GetMapping("/custom")
public String customApi() {
return "This API has custom IP whitelist rules";
}
}
3.7 注意事項
IP 獲取問題:
- 如果使用 Nginx 等反向代理,需從
X-Forwarded-For頭獲取真實 IP。 - 示例代碼已處理代理邏輯。
- 如果使用 Nginx 等反向代理,需從
通配符支持:
- 如果需要支持 CIDR 格式(如
192.168.1.0/24),需自行實現(xiàn) CIDR 匹配邏輯。
- 如果需要支持 CIDR 格式(如
性能優(yōu)化:
- 動態(tài)白名單建議使用緩存(如 Redis)減少數(shù)據(jù)庫查詢。
- 高并發(fā)場景下,F(xiàn)ilter 或 AOP 的性能開銷需評估。
安全性:
- 確保白名單邏輯不被繞過(如偽造
X-Forwarded-For頭)。 - 結(jié)合其他安全措施(如 HTTPS、JWT)增強防護。
- 確保白名單邏輯不被繞過(如偽造
四、進階實現(xiàn):基于Spring Security的專業(yè)方案
4.1 Spring Security集成概述
對于企業(yè)級應(yīng)用,使用Spring Security可以提供更專業(yè)的安全控制。我們將基于前面的基礎(chǔ)實現(xiàn),重構(gòu)為Spring Security方案。
添加Spring Security依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
4.2 自定義AuthenticationFilter
創(chuàng)建IpAuthenticationFilter:
public class IpAuthenticationFilter extends OncePerRequestFilter {
private final IpWhitelistProperties properties;
private final ObjectMapper objectMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 獲取請求路徑對應(yīng)的HandlerMethod
HandlerExecutionChain handlerExecutionChain = null;
try {
handlerExecutionChain = ((DispatcherServlet) request.getAttribute(DispatcherServlet.class.getName() + ".CONTEXT"))
.getHandler(request);
} catch (Exception e) {
filterChain.doFilter(request, response);
return;
}
if (handlerExecutionChain == null || !(handlerExecutionChain.getHandler() instanceof HandlerMethod)) {
filterChain.doFilter(request, response);
return;
}
HandlerMethod handlerMethod = (HandlerMethod) handlerExecutionChain.getHandler();
// 后續(xù)邏輯與Interceptor類似...
}
}
4.3 安全配置類
創(chuàng)建安全配置類:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final IpWhitelistProperties ipWhitelistProperties;
private final ObjectMapper objectMapper;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.addFilterBefore(new IpAuthenticationFilter(ipWhitelistProperties, objectMapper),
UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/api/public").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().disable()
.httpBasic().disable();
}
}
4.4 基于表達式的安全控制
Spring Security支持使用@PreAuthorize注解實現(xiàn)更靈活的控制:
@RestController
@RequestMapping("/api/v2")
public class SecureController {
@PreAuthorize("@ipSecurityService.isAllowed(#request)")
@GetMapping("/expression")
public String expressionBasedApi(HttpServletRequest request) {
return "This API uses expression-based IP control";
}
}
@Service
public class IpSecurityService {
public boolean isAllowed(HttpServletRequest request) {
// 實現(xiàn)IP檢查邏輯
return true;
}
}
五、生產(chǎn)級增強功能
5.1 動態(tài)IP白名單管理
實現(xiàn)動態(tài)更新白名單而不重啟應(yīng)用:
@Service
public class DynamicIpWhitelistService {
private final List<String> dynamicAllowedIps = new CopyOnWriteArrayList<>();
private final List<String> dynamicAllowedIpRanges = new CopyOnWriteArrayList<>();
public synchronized void addAllowedIp(String ip) {
if (IpUtils.isValidIp(ip) && !dynamicAllowedIps.contains(ip)) {
dynamicAllowedIps.add(ip);
}
}
public synchronized void removeAllowedIp(String ip) {
dynamicAllowedIps.remove(ip);
}
public synchronized void reloadIps(List<String> ips) {
dynamicAllowedIps.clear();
dynamicAllowedIps.addAll(ips.stream()
.filter(IpUtils::isValidIp)
.collect(Collectors.toList()));
}
// 類似方法實現(xiàn)IP段管理...
}
5.2 結(jié)合Redis的分布式IP白名單
對于分布式系統(tǒng),白名單需要集中存儲:
@Configuration
public class RedisIpWhitelistConfig {
@Bean
public RedisTemplate<String, String> ipWhitelistRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
@Service
@RequiredArgsConstructor
public class RedisIpWhitelistService {
private static final String WHITELIST_KEY = "ip:whitelist";
private static final String WHITELIST_RANGES_KEY = "ip:whitelist:ranges";
private final RedisTemplate<String, String> redisTemplate;
public boolean isAllowed(String ip) {
// 檢查精確IP
Boolean isMember = redisTemplate.opsForSet().isMember(WHITELIST_KEY, ip);
if (Boolean.TRUE.equals(isMember)) {
return true;
}
// 檢查IP段
Set<String> ranges = redisTemplate.opsForSet().members(WHITELIST_RANGES_KEY);
if (ranges != null) {
return ranges.stream().anyMatch(range -> IpUtils.isIpInRange(ip, range));
}
return false;
}
// 其他管理方法...
}
5.3 性能優(yōu)化與緩存
實現(xiàn)本地緩存減少遠程調(diào)用:
@Service
public class CachedIpWhitelistService {
private final LoadingCache<String, Boolean> ipCheckCache;
public CachedIpWhitelistService(RedisIpWhitelistService redisService) {
this.ipCheckCache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(redisService::isAllowed);
}
public boolean isAllowed(String ip) {
return Boolean.TRUE.equals(ipCheckCache.get(ip));
}
}
六、測試策略與驗證
6.1 單元測試
針對核心工具類編寫單元測試:
class IpUtilsTest {
@Test
void testIsIpInRange() {
assertTrue(IpUtils.isIpInRange("192.168.1.100", "192.168.1.0/24"));
assertFalse(IpUtils.isIpInRange("10.0.0.5", "192.168.1.0/24"));
}
@Test
void testGetClientIp() {
// 模擬HttpServletRequest測試各種頭部情況
}
}
6.2 集成測試
使用MockMvc測試完整流程:
@SpringBootTest
@AutoConfigureMockMvc
class IpWhitelistIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser
void testPublicApi() throws Exception {
mockMvc.perform(get("/api/public"))
.andExpect(status().isOk());
}
@Test
@WithMockUser
void testSecureApiWithAllowedIp() throws Exception {
mockMvc.perform(get("/api/secure").with(request -> {
request.setRemoteAddr("192.168.1.100");
return request;
}))
.andExpect(status().isOk());
}
@Test
@WithMockUser
void testSecureApiWithDeniedIp() throws Exception {
mockMvc.perform(get("/api/secure").with(request -> {
request.setRemoteAddr("10.1.2.3");
return request;
}))
.andExpect(status().isForbidden());
}
}
6.3 性能測試
使用JMeter模擬不同負載下的表現(xiàn):

七、生產(chǎn)環(huán)境最佳實踐
7.1 安全建議
- 最小權(quán)限原則:只添加必要的IP到白名單
- 定期審計:每月審查白名單,移除不再需要的IP
- 日志記錄:詳細記錄所有被拒絕的訪問嘗試
- 監(jiān)控告警:對異常訪問模式設(shè)置告警
- 備份機制:定期備份白名單配置
7.2 性能調(diào)優(yōu)
- 緩存策略:對IP檢查結(jié)果進行適當緩存
- 異步檢查:對于非關(guān)鍵路徑可以考慮異步驗證
- CIDR優(yōu)化:將IP段檢查算法優(yōu)化為O(1)復(fù)雜度
- 并發(fā)控制:使用線程安全的數(shù)據(jù)結(jié)構(gòu)
- 預(yù)熱機制:應(yīng)用啟動時預(yù)加載常用IP
7.3 故障排查指南
常見問題及解決方案:
| 問題現(xiàn)象 | 可能原因 | 解決方案 |
|---|---|---|
| 合法IP被拒絕 | IP獲取不正確 | 檢查X-Forwarded-For等頭部配置 |
| 白名單修改后不生效 | 緩存未刷新 | 實現(xiàn)配置變更通知機制 |
| 性能下降 | IP檢查成為瓶頸 | 引入緩存、優(yōu)化算法或水平擴展 |
| 分布式環(huán)境不一致 | 各節(jié)點白名單不同步 | 使用集中式存儲如Redis |
| IPv6支持問題 | 只配置了IPv4 | 確保同時支持IPv4和IPv6格式 |
八、擴展與演進
8.1 結(jié)合微服務(wù)架構(gòu)
在Spring Cloud體系中,可以在網(wǎng)關(guān)層統(tǒng)一實現(xiàn)IP白名單:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("secure-service", r -> r.path("/api/secure/**")
.filters(f -> f.filter(new IpWhitelistGatewayFilter()))
.uri("lb://secure-service"))
.build();
}
8.2 Kubernetes環(huán)境適配
在K8s中需要考慮Pod IP動態(tài)變化的問題:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-whitelist
spec:
podSelector:
matchLabels:
app: spring-boot-app
ingress:
- from:
- ipBlock:
cidr: 192.168.1.0/24
ports:
- protocol: TCP
port: 8080
8.3 未來演進方向
- 機器學(xué)習(xí)分析:自動識別異常IP并動態(tài)調(diào)整白名單
- 區(qū)塊鏈存證:將白名單變更記錄上鏈確保不可篡改
- 零信任整合:與零信任架構(gòu)深度集成
- IoT擴展:支持設(shè)備指紋等更多維度的認證
- 量子安全:為后量子時代提前準備加密方案
九、總結(jié)與展望
本文詳細探討了在Spring Boot應(yīng)用中實現(xiàn)IP白名單控制的多種方案,從基礎(chǔ)的Interceptor實現(xiàn)到基于Spring Security的專業(yè)方案,再到生產(chǎn)級的增強功能和分布式環(huán)境適配。通過本教程,您應(yīng)該能夠:
- 深入理解IP白名單的原理和價值
- 掌握在Spring Boot中實現(xiàn)IP控制的多種技術(shù)
- 具備構(gòu)建生產(chǎn)級IP白名單系統(tǒng)的能力
- 了解相關(guān)的最佳實踐和優(yōu)化策略
IP白名單作為網(wǎng)絡(luò)安全的基礎(chǔ)設(shè)施之一,在云原生和微服務(wù)架構(gòu)不斷演進的今天,仍然發(fā)揮著不可替代的作用。未來,隨著邊緣計算和5G技術(shù)的普及,IP白名單技術(shù)可能會與更多新興技術(shù)融合,形成更智能、更靈活的訪問控制體系。
到此這篇關(guān)于SpringBoot中IP白名單控制實現(xiàn)限制接口訪問的文章就介紹到這了,更多相關(guān)SpringBoot IP白名單 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實現(xiàn)簡單的銀行管理系統(tǒng)的示例代碼
這篇文章主要介紹了如何利用Java實現(xiàn)簡單的銀行管理系統(tǒng),可以實現(xiàn)存款,取款,查詢等功能,文中的示例代碼講解詳細,感興趣的可以了解一下2022-09-09
spring batch使用reader讀數(shù)據(jù)的內(nèi)存容量問題詳解
這篇文章主要介紹了spring batch使用reader讀數(shù)據(jù)的內(nèi)存容量問題詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java Dubbo協(xié)議下的服務(wù)端線程使用詳解
Dubbo是阿里開源項目,國內(nèi)很多互聯(lián)網(wǎng)公司都在用,已經(jīng)經(jīng)過很多線上考驗。Dubbo內(nèi)部使用了Netty、Zookeeper,保證了高性能高可用性,使用Dubbo可以將核心業(yè)務(wù)抽取出來,作為獨立的服務(wù),逐漸形成穩(wěn)定的服務(wù)中心2023-03-03
Spring SpringMVC,Spring整合MyBatis 事務(wù)配置的詳細流程
這篇文章給大家介紹SSM整合詳細流程步驟 Spring SpringMVC,Spring整合MyBatis 事務(wù)配置,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-10-10
mybatis-plus如何配置自定義數(shù)據(jù)類型TypeHandle
JAVA技術(shù)實現(xiàn)上傳下載文件到FTP服務(wù)器(完整)

