业务开发时,接口不能对外暴露怎么办?
在业务开发中,通常会遇到某些接口仅限于内部服务调用,不能对外暴露的需求。为了满足这样的需求,我们可以采取多种方法来控制接口的访问范围,从而确保只有内网的服务可以调用这些接口,而外部用户不能直接访问。
以下是几种常见的实现方式:
1. 通过 API 网关进行访问控制
如果你的系统架构中使用了 API 网关(例如:Spring Cloud Gateway、Zuul、Nginx 等),你可以配置网关来限制某些接口的访问权限,只允许内网的服务访问,而外部请求会被拒绝。
示例:使用 Spring Cloud Gateway 限制外部访问
spring:cloud:gateway:routes:- id: internal_serviceuri: http://internal-service:8080predicates:- Path=/internal/** # 只允许访问 `/internal/**` 路径filters:- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 10redis-rate-limiter.burstCapacity: 20metadata:security: internal # 用于标识此接口仅限内网访问
原理:
- API 网关 可以通过 IP 白名单或基于请求头等方式来对接口进行访问控制。通过配置可以确保只有从内网服务发出的请求能访问这些接口。
获取Idea插件:https://web.52shizhan.cn/paid-activate-code
2. 基于 IP 白名单控制访问
在 Spring Boot 中,你可以通过配置 Spring Security 或者 Nginx 来实现基于 IP 地址的访问控制,限制某些接口只能在特定的 IP 地址范围内访问。
示例:基于 IP 白名单限制接口访问
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/internal/**").hasIpAddress("192.168.0.0/16") // 允许内网 IP 访问.anyRequest().authenticated() // 其他请求需要身份验证.and().httpBasic(); // 启用基础 HTTP 验证(可根据需求修改)}
}
原理:
- 使用 Spring Security 配合 IP 地址检查,可以对指定路径(如
/internal/**
)限制为特定 IP 地址范围(如内网 IP)。只有匹配的 IP 地址能够访问这些接口。
3. 通过自定义注解和 AOP 控制访问
通过自定义注解和 AOP(面向切面编程)技术,结合 ServletRequest
来获取请求源 IP 或请求头信息,来实现自定义的访问控制逻辑。
示例:自定义注解 + AOP 访问控制
- 定义注解:首先定义一个注解,表示某些接口是内网接口。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InternalOnly {
}
- 实现 AOP 切面:然后创建一个 AOP 切面,检查请求的源 IP,只有内网请求可以访问被
@InternalOnly
注解标记的方法。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;@Aspect
@Component
public class AccessControlAspect {private final HttpServletRequest request;public AccessControlAspect(HttpServletRequest request) {this.request = request;}@Pointcut("@annotation(com.example.InternalOnly)")public void internalOnlyMethods() {}@Before("internalOnlyMethods()")public void checkIp() {String clientIp = request.getRemoteAddr();if (!clientIp.startsWith("192.168")) { // 只允许内网 IPthrow new AccessDeniedException("Access denied for external requests.");}}
}
- 应用注解:
@RestController
public class InternalController {@InternalOnly@GetMapping("/internal/data")public String getInternalData() {return "Internal Data";}
}
原理:
- 通过自定义注解标记内网接口,然后通过 AOP 在方法调用前检查请求的源 IP 是否符合内网访问的要求。若不符合,则抛出
AccessDeniedException
。
4. 使用 Spring Cloud 或微服务架构中的 @Profile
控制环境访问
如果你使用的是 Spring Cloud 或微服务架构,可以通过 @Profile
注解根据不同的环境进行控制。例如,在开发环境或测试环境中暴露某些接口,而在生产环境中不暴露这些接口。
示例:使用 @Profile
控制接口暴露
@RestController
@Profile("!prod") // 在非生产环境下暴露接口
public class InternalController {@GetMapping("/internal/data")public String getInternalData() {return "Internal Data for non-prod environments";}
}
原理:
- 使用
@Profile
注解,可以根据 Spring Boot 启动时的配置文件来选择是否加载某个 Bean,从而控制接口的暴露。这种方式适合在不同环境下灵活控制接口的可用性。
5. 使用 API Key 或 Token 进行验证
通过在请求中附加 API Key 或 Token,确保只有内网服务或者授权的服务才能调用接口。你可以在请求头中传递 API Key 或 Token,服务端对其进行验证。
示例:基于 API Key 验证
@RestController
public class SecureController {private static final String API_KEY = "internal-api-key";@GetMapping("/secure/data")public String getSecureData(@RequestHeader("API-Key") String apiKey) {if (!API_KEY.equals(apiKey)) {throw new AccessDeniedException("Invalid API Key");}return "Secure Data";}
}
原理:
- 在每个请求中附加 API Key 或 Token,服务端对其进行验证,确保只有持有有效 Key 的服务才能访问接口。你可以选择将 API Key 固定在配置文件中,或者使用 OAuth 2.0、JWT 等认证方式。
总结
在业务开发中,针对只能内网访问的接口需求,可以采取以下几种策略:
- API 网关:通过 API 网关进行访问控制,限制外部访问。
- IP 白名单:通过 Spring Security 或 Nginx 配置 IP 白名单,限制特定 IP 地址的访问。
- 自定义注解 + AOP:使用自定义注解和 AOP 进行灵活的访问控制。
- Profile 控制:通过
@Profile
注解根据环境控制接口暴露。 - API Key 或 Token 验证:通过 API Key 或 Token 验证服务的访问权限。
选择合适的方式来确保接口只对内网暴露,保护你的服务免受外部访问的影响。