当前位置: 首页 > 科技观察

业务开发中接口不能对外暴露怎么办?

时间:2023-03-12 12:32:24 科技观察

在业务开发中,我们经常会遇到这样的实际需求,即某个接口不能对外暴露,只能在内网服务之间调用。面对这样的情况,我们该如何实现呢?今天我们就来看看这个问题,从几个可行方案中选择一个来实现吧。1.内外网接口微服务隔离将对外暴露的接口和对内暴露的接口分别放在两个微服务上。一个服务中的所有接口都是对外暴露的,另一个服务的接口只能在内网服务之间调用。.该方案需要额外编写一个只暴露内部接口的微服务,将所有只能对内部暴露的业务接口聚合到这个微服务中,通过这个聚合的微服务从各个业务端获取资源。在该方案中,新增了一个微服务用于请求转发,增加了系统的复杂度,增加了调用的耗时和后期的维护成本。2.网关+redis实现了白名单机制。redis中维护了一组接口白名单列表。当外部请求到达网关时,从redis获取接口白名单,允许白名单中的接口,否则拒绝。这种方案的好处是不侵入业务代码,只需要维护白名单;缺点是白名单的维护是一项持续的投资工作。很多公司业务开发不能直接接触redis,只能提交工单申请,增加了开发成本;另外每次有请求进来都需要判断白名单,增加了系统响应的耗时。考虑到正常情况下,大部分外部请求都在白名单中,只有极少数的恶意请求会被白名单机制拦截,所以该方案的性价比很低。3、方案三网关+AOP与方案二中接口的白名单判断相比,方案三是对请求的来源进行判断,并将判断下沉到服务端。避免了网关侧的逻辑判断,从而提高了系统响应速度。我们知道,从外部传入的请求,都会经过网关,然后分发到具体的业务端。内部服务之间的调用不需要经过外部网关(k8s服务)。该方案将内外网访问权限的处理分散到各个业务端,解决了网关处理的系统瓶颈;同时,开发者可以在业务端直接确定接口的内外网访问权限,提高开发效率。增加了代码的可读性。当然这种方案对业务代码会有一定的侵入性,但是可以通过注解的形式将这种侵入性降到最低。具体实操下面是第三种方案,进行具体的代码演示。首先,在网关端,需要在传入的请求头中添加一个外部网络标识符:from=public。@ComponentpublicclassAuthFilterimplementsGlobalFilter,Ordered{@OverridepublicMonofilter(ServerWebExchangeexchange,GatewayFilterChain链){returnchain.filter(exchange.mutate().request(exchange.getRequest().mutate().header("id","").header("from","public").build()).build());}@OverridepublicintgetOrder(){返回0;接下来编写内外网访问权限判断AOP和注解。@Aspect@Component@Slf4jpublicclassOnlyIntranetAccessAspect{@Pointcut("@within(org.openmmlab.platform.common.annotation.OnlyIntranetAccess)")publicvoidonlyIntranetAccessOnClass(){}@Pointcut("@annotation(org.openmmlab.platform.common.annotation.OnlyIntranetAccess)")publicvoidonlyIntranetAccessOnMethed(){}@Before(value="onlyIntranetAccessOnMethed()||onlyIntranetAccessOnClass()")publicvoidbefore(){HttpServletRequesthsr=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();Stringfrom=hsr.getHeader("from");if(!StringUtils.isEmpty(from)&&"public".equals(from)){log.error("此api只允许内网源调用");抛出新的MMException(ReturnEnum.C_NETWORK_INTERNET_ACCESS_NOT_ALLOWED_ERROR);}}}@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceOnlyIntranetAccess{}最后在只能内网访问的接口上加上@OnlyIntranetAccess注解@GetMapping("/role/add")@OnlyIntranetAccesspublicStringonlyIntranetAccess(){return"该接口只允许内部服务调用";}