Write it down while it’s hot for your future self

0 – preface

During service development, an interface can only be invoked between Intranet services. Faced with such a situation, how can we achieve it? Today, we’re going to take a look at this problem and choose one of several possible solutions to implement it.

1 – Feasible solution

At present, there are three schemes in mind: Intranet interface isolation through microservices, Redis and gateway to achieve interface whitelist mechanism, gateway plus AOP to judge access rights in business side.

1.1 Solution 1 Intranet interface microservice Isolation

The externally exposed and internally exposed interfaces are placed on two microservices respectively. All interfaces in one service are exposed externally, and the interfaces of the other service can only be invoked between Intranet services.

In this scheme, we need to write an additional micro-service that only exposes interfaces internally, and aggregate all business interfaces that can only be exposed internally into this micro-service. Through this aggregated micro-service, we can obtain resources from each business side respectively.

In this scheme, a new micro-service is added for request forwarding, which increases the complexity of the system, the call time and the later maintenance cost.

1.2 Solution 2 Gateway + Redis Implements the whitelist mechanism

Maintain a set of interface whitelists in Redis. When an external request reaches the gateway, redis obtains the interface whitelist. The interface in the whitelist is allowed, and the interface in the whitelist is denied.

The advantage of this scheme is that the business code is zero intrusion, only need to maintain a good whitelist list;

The disadvantage is that the maintenance of the whitelist is a continuous investment. In many companies, business development cannot directly touch Redis, but can only apply for work orders, which increases the development cost. In addition, each incoming request needs to determine the whitelist, which increases the response time of the system. Considering that most incoming requests are in the whitelist and only a few malicious requests are blocked by the whitelist mechanism, the cost performance of this scheme is very low.

1.3 Plan three gateway + AOP

Compared with scheme 2, scheme 3 determines the source of the request and lowers the judgment to the service side. This avoids logical judgment on the gateway and improves system response speed.

As we know, external requests must pass through the gateway and then be distributed to the specific business side, and calls between internal services do not need to go through the external gateway (through K8S service). According to this characteristic, we can all through the gateway of the request to add a field in the header, the business side of the interface after receiving the request, to determine whether there is the field in the header, if so, then the request from the outside, no, belong to internal service calls, according to whether the interface belongs to the internal interface to decide whether to release the request.

In this scheme, the access permission of Intranet and extranet is distributed to each business side, which eliminates the systematic bottleneck of gateway. At the same time, developers can directly determine the access permission of the interface on the business side, which improves the development efficiency and increases the readability of the code.

Of course, this solution can be somewhat intrusive to the business code, but it can be minimized by means of annotations.

2 – Concrete operation

The following is a specific code demonstration of scheme 3.

First on the gateway side, you need to add an external identifier to the incoming request header: from=public

@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", ""). The header (" from", "public"). The build ()). The build ()); } @Override public int getOrder () { return 0; }}Copy the code

Next, write AOP and annotations for extranet access judgment

@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 onlyIntranetAccessOnMethed () {
 }

 @Before ( value = "onlyIntranetAccessOnMethed() || 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 {
}
Copy the code

Finally, add the @onlyintranetAccess annotation to the interfaces that are only Intranet accessible

@getIntranetAccess ("/role/add") @onlyintranetAccess Public String OnlyIntranetAccess () {return "This interface allows only internal service calls "; }Copy the code

The above.