How to Restrict Certain APIs to Internal Calls Only in a Microservice Architecture
This article examines three practical approaches for preventing external exposure of specific APIs—service isolation, gateway‑based Redis whitelist, and gateway‑plus‑AOP—evaluates their trade‑offs, and provides step‑by‑step Java code to implement the preferred AOP solution in a Spring Cloud environment.
When a business requirement dictates that some endpoints must be callable only within the internal network, the author first outlines three feasible designs and then selects the most suitable one.
1. Separate Microservices for Internal and External APIs
The idea is to create two microservices: one exposing all public APIs and another aggregating only the internal‑only APIs. Requests to internal endpoints are routed through the internal service, which forwards calls to the appropriate business services.
Pros: clear separation of concerns.
Cons: introduces an extra microservice, adds request‑forwarding latency, and increases maintenance complexity.
2. Gateway + Redis Whitelist
A Redis set stores the whitelist of allowed internal APIs. When a request reaches the API gateway, the gateway checks the Redis list; if the endpoint is in the whitelist, the request is allowed, otherwise it is rejected.
Advantages: zero intrusion into business code; only the whitelist needs to be maintained.
Drawbacks: maintaining the whitelist requires continuous effort—many teams cannot modify Redis directly and must submit tickets, raising operational cost. Moreover, every request incurs a Redis lookup, adding latency, and the benefit is limited because most external traffic will be whitelisted anyway, making the cost‑benefit ratio low.
3. Gateway + AOP (Chosen Solution)
Instead of checking the whitelist at the gateway, this approach pushes the decision to the business side using an AOP interceptor. The gateway adds a custom header (e.g., from=public) to external requests. Business services inspect this header; if it is present, the request is treated as external, otherwise it is considered internal.
Benefits:
Eliminates the gateway bottleneck caused by per‑request whitelist checks.
Developers can determine access rights directly in the service, improving readability and reducing response time.
Implementation can be lightweight by using a custom annotation to mark internal‑only methods, minimizing code intrusion.
Potential downside: introduces some code intrusion, but this is mitigated by using an annotation‑driven AOP aspect.
Implementation Details
1. Add a header on the gateway side to mark external traffic:
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> 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; }
}2. Define an AOP aspect and a custom annotation to enforce internal‑only access:
@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 request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String from = request.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 {}3. Apply the annotation to any endpoint that must be internal‑only:
@GetMapping("/role/add")
@OnlyIntranetAccess
public String onlyIntranetAccess() {
return "该接口只允许内部服务调用";
}The accompanying image illustrates the flow of adding the header at the gateway and the subsequent AOP check in the business service.
By following these steps, developers can enforce internal‑only access without adding a separate microservice or a Redis‑based whitelist, achieving lower latency and clearer responsibility boundaries.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.
