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

SpringCloudAlibaba微服务隐私接口禁止外部访问

时间:2023-03-13 00:04:01 科技观察

本文转载自微信公众号《JAVA日知录》,作者飘渺果酱。转载本文请联系JAVA日知录公众号。大家好,我是飘渺!在SpringCloud实战系列中,我已经介绍了在SpringCloud体系下如何防止前端请求绕过网关直接到达后端微服务。今天我们反其道而行之,介绍一下在SpringCloud系统中是怎么做的。防止内部隐私接口被网关调用。有的同学看到这里可能会觉得有点头晕。怎么会有这样的业务场景?别着急,先回顾一下我们的业务场景。业务场景客户端通过网关调用OrderService服务获取数据,OrderService通过Feign调用AccountService服务。AccountService提供相应的Feign接口后,客户端可以直接通过网关调用AccountService接口。现在假设AccountService提供的接口包含一些私有数据,只允许内部调用辅助OrderService进行业务逻辑处理,不允许客户端直接获取。这个时候我们需要做什么?在业务实践中,我们首先通过代码实现原来的流程,即通过网关调用OrderService的OrderController,然后在OrderController中通过Feign调用AccountService的AccountController。为了阅读方便,文中删除了一些无用的代码。模拟现实入口OrderControllerpublicclassOrderController{privatefinalOrderServiceorderService;privatefinalAccountClientaccountClient;@GetMapping("/order/{orderNo}")publicResultDatagetById(@PathVariable("orderNo")StringorderNo){OrderDTOorderDTO=orderService.selectByNo(orderNo);ResultDatasecretValue=accountClient.getSecretValue();log.info(secretValue);returnResultData.success(orderDTO);}}在OrderController中通过AccountClient调用AccountServiceResultDatasecretValue=accountClient.getSecretValue();Feign接口publicinterfaceAccountApi{...@GetMapping("/account/getSecretValue")ResultDatagetSecretValue();...}AccountController实现@RestController@Log4j2@Api(tags="account接口")@RequiredArgsConstructor(onConstructor=@__(@Autowired))publicclassAccountControllerimplementsAccountApi{/***隐私接口,禁止通过网络访问*/@Override@GetMapping("/account/getSecretValue")publicResultDatagetSecretValue(){returnResultData.success("Privacy接口,禁止通过网关访问");}}前面说过,一旦提供了Feign接口,我们默认可以直接通过网关访问getSecretValue()方法,那么如何保证这个方法不允许外部调用呢?网上大部分的解决方案都是基于黑名单机制,将这些接口放入“黑名单”中存储起来。网关启动时,会读取黑名单配置,然后进行验证。是否在黑名单中确实可以,但总感觉不够灵活,实现起来也比较繁琐,这里就不展开了。今天介绍的是使用访问路径来实现,非常简单轻量。实现原理我们需要使用接口路径规范来实现,即在为接口指定访问路径时,我们使用这样的格式:/accesscontrol/interface。访问控制可以有如下规则(参考JAVA包规范),可以根据业务需要进行扩展。pb-public的所有请求都可以访问pt-protected,只有通过token认证才能访问。pv-private无法通过网关访问,只能由微服务内部调用df-default网关请求token认证访问,请求参数和返回结果加解密...有这套接口规范,我们可以灵活控制接口的访问权限,然后在网关验证接口路径。如果命中相应的访问控制规则,则进行相应的逻辑处理。代码实战知道了实现原理,写代码就很简单了。修改接口访问路径,按照接口路径规范publicinterfaceAccountApi{@GetMapping("/pv/account/getSecretValue")ResultDatagetSecretValue();}修改feign的访问路径。@RestController@Log4j2@Api(tags="accountinterface")@RequiredArgsConstructor(onConstructor=@__(@Autowired))publicclassAccountControllerimplementsAccountApi{/***隐私接口,禁止通过网关访问*/@Override@GetMapping("/pv/account/getSecretValue")publicResultDatagetSecretValue(){returnResultData.success("隐私接口,禁止通过网关访问");}}修改接口实现类的访问路径,需要与Feign的路径。接口验证的网关自定义拦截器@Component@Order(0)@Slf4jpublicclassGatewayRequestFilterimplementsGlobalFilter{@OverridepublicMonofilter(ServerWebExchangeexchange,GatewayFilterChainchain){//获取请求路径StringrawPath=exchange.getRequest().getURI().getRawPath();if(isPv(rawPath)){thrownewHttpServerErrorException(HttpStatus.FORBIDDEN,"can'taccessprivateAPI");}returnchain.filter(newExchange);}/***判断是否内部私有方法*@paramrequestURI请求路径*@returnboolean*/privatebooleanisPv(StringrequestURI){returnisAccess(requestURI,"/pv");}/***网关访问控制验证*/privatebooleanisAccess(StringrequestURI,Stringaccess){//后端标准请求路径为/访问控制/请求路径intindex=requestURI.indexOf(access);returnindex>=0&&StringUtils.countOccurrencesOf(requestURI.substring(0,index),"/")<1;}}通过以上两个简单的步骤,我们就可以实现本文提出的问题,接下来我们来测试一下出去。测试直接访问后端服务,提示无法访问。通过OrderService访问后端服务才能正常访问。总结保证内部隐私接口不被外界访问。相信做微服务开发的同学基本都会遇到。本文提供的方案代码量小,接口路径规范可以根据自己的业务规则进行修改扩展。推荐大家使用。其实代码不是关键,关键是让团队遵守这个接口规范,想法比实现更重要。