Implementing Internal‑Only API Access with Gateway, Redis Whitelist, and AOP in Spring Cloud
The article explains three approaches for restricting certain APIs to internal service calls—microservice isolation, a gateway‑plus‑Redis whitelist, and a gateway‑plus‑AOP solution—then provides step‑by‑step Spring Cloud code to add a public‑source header, define an AOP aspect with a custom annotation, and annotate internal‑only endpoints.
When developing business services, you may encounter APIs that must not be exposed externally and should only be callable between internal services. The article reviews three practical solutions and selects one for implementation.
1. Microservice Isolation
Separate public and internal APIs into two distinct microservices: one exposing all endpoints to the outside world, and another exposing only internal endpoints for intra‑network calls. This adds a new service for request forwarding, increasing system complexity, latency, and maintenance cost.
2. Gateway + Redis Whitelist
Maintain an API whitelist in Redis; the gateway checks each incoming request against this list, allowing requests on the whitelist and rejecting others. This approach is non‑intrusive to business code but requires continuous whitelist management and adds per‑request latency, making its cost‑benefit ratio low.
3. Gateway + AOP
Instead of checking the whitelist at the gateway, this method adds a marker in the request header (e.g., from=public ) and lets the business side determine whether the call is internal or external. By using an AOP aspect and a custom annotation, the internal‑only check is delegated to the service layer, reducing gateway load and improving response speed, though it introduces some code intrusion that can be mitigated with annotations.
Code Demonstration
Step 1: Add a public‑source header in the gateway filter.
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(
exchange.mutate().request(
exchange.getRequest().mutate()
.header("id", "")
.header("from", "public")
.build())
.build()
);
}
@Override
public int getOrder() {
return 0;
}
}Step 2: Define the AOP aspect and the custom annotation.
@Aspect
@Component
@Slf4j
public class OnlyIntranetAccessAspect {
@Pointcut("@within(org.openmmlab.platform.common.annotation.OnlyIntranetAccess)")
public void onlyIntranetAccessOnClass() {}
@Pointcut("@annotation(org.openmmlab.platform.common.annotation.OnlyIntranetAccess)")
public void onlyIntranetAccessOnMethod() {}
@Before("onlyIntranetAccessOnMethod() || onlyIntranetAccessOnClass()")
public void before() {
HttpServletRequest hsr = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String from = hsr.getHeader("from");
if (!StringUtils.isEmpty(from) && "public".equals(from)) {
log.error("This api is only allowed invoked by intranet source");
throw new MMException(ReturnEnum.C_NETWORK_INTERNET_ACCESS_NOT_ALLOWED_ERROR);
}
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OnlyIntranetAccess {}Step 3: Annotate an internal‑only endpoint.
@GetMapping("/role/add")
@OnlyIntranetAccess
public String onlyIntranetAccess() {
return "该接口只允许内部服务调用";
}By applying the @OnlyIntranetAccess annotation, the aspect intercepts calls and blocks any request that carries the from=public header, ensuring the API can be invoked only by internal services.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.