文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringCloud Alibaba微服务实战之隐私接口禁止外部访问

2024-12-03 00:55

关注

本文转载自微信公众号「JAVA日知录」,作者飘渺Jam。转载本文请联系JAVA日知录公众号。

大家好,我是飘渺!

在SpringCloud实战系列文章中曾经介绍过在SpringCloud体系下如何防止前端请求绕过网关直接到达后端微服务,今天我们要反其道而行之,介绍在SpringCloud体系中如何防止内部隐私接口被网关调用。

看到这里可能有的同学会有点晕,怎么还有这种业务场景呢,别急,咱们先回顾一下我们的业务场景。

业务场景

客户端通过网关调用OrderService服务获取数据,OrderService通过Feign调用AccountService服务,而当AccountService提供对应的Feign接口后,客户端是可以通过网关直接调用AccountService接口的。

现在假设AccountService提供的接口包含了部分隐私数据,只允许内部调用协助OrderService进行业务逻辑处理,不允许客户端直接获取,此时咱们需要怎么做?

业务实战

我们先通过代码将原始的流程实现出来,即通过网关调用OrderService的OrderController,然后在OrderController中通过Feign调用AccountService的AccountController,为了便于阅读,文章中删除了部分无用代码。

模拟实现

入口 OrderController

  1. public class OrderController { 
  2.     private final OrderService orderService; 
  3.     private final AccountClient accountClient; 
  4.  
  5.  
  6.     @GetMapping("/order/{orderNo}"
  7.     public ResultData getById(@PathVariable("orderNo") String orderNo){ 
  8.         OrderDTO orderDTO = orderService.selectByNo(orderNo); 
  9.         ResultData secretValue = accountClient.getSecretValue(); 
  10.         log.info(secretValue); 
  11.         return ResultData.success(orderDTO); 
  12.     } 

在OrderController中通过AccountClient调用AccountService

  1. ResultData secretValue = accountClient.getSecretValue(); 

Feign接口

  1. public interface AccountApi { 
  2.   ... 
  3.     @GetMapping("/account/getSecretValue"
  4.     ResultData getSecretValue(); 
  5.   ... 

AccountController实现

  1. @RestController 
  2. @Log4j2 
  3. @Api(tags = "account接口"
  4. @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
  5. public class AccountController implements AccountApi { 
  6.  
  7.      
  8.     @Override 
  9.     @GetMapping("/account/getSecretValue"
  10.     public ResultData getSecretValue() { 
  11.         return ResultData.success("隐私接口,禁止通过网关访问"); 
  12.     } 
  13.      

正如我们前面所说,一旦提供了Feign接口,在默认情况下我们可以直接通过网关访问getSecretValue()方法,那怎么确保这个方法不让外部调用呢?

解决方案

网上现在大部分的解决办法是基于黑名单机制,即将这些接口放入“黑名单”中存储起来,在网关启动时读取黑名单配置,然后校验是否在黑名单中。

这种办法确实也可以,但是总感觉不够灵活,而且实现也比较繁琐,这里就不展开了。

我们今天介绍的是利用访问路径来实现,非常简单轻便。

实现原理

我们需要借助接口路径规范来实现,即给接口指定访问路径时采用这样的格式 : /访问控制/接口。

访问控制可以有以下几个规则(参考JAVA包规范),可根据业务需要进行扩展。

  1. pb - public 所有请求均可访问 
  2.  
  3. pt - protected 需要进行token认证通过后方可访问 
  4.  
  5. pv - private 无法通过网关访问,只能微服务内部调用 
  6.  
  7. df - default 网关请求token认证,并且请求参数和返回结果进行加解密 
  8.  
  9. ... 

有了这套接口规范以后,我们就可以灵活控制接口访问权限,然后在网关对接口路径进行校验,如果命中对应的访问控制规则就进行对应的逻辑处理。

代码实战

既然知道了实现原理,那写代码就很简单了。

修改接口访问路径,遵循接口路径规范

  1. public interface AccountApi { 
  2.     @GetMapping("/pv/account/getSecretValue"
  3.     ResultData getSecretValue(); 

修改feign的访问路径。

  1. @RestController 
  2. @Log4j2 
  3. @Api(tags = "account接口"
  4. @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
  5. public class AccountController implements AccountApi { 
  6.  
  7.      
  8.     @Override 
  9.     @GetMapping("/pv/account/getSecretValue"
  10.     public ResultData getSecretValue() { 
  11.         return ResultData.success("隐私接口,禁止通过网关访问"); 
  12.     } 
  13.      

修改接口实现类的访问路径,这里需要与Feign的路径保持一致。

网关自定义拦截器进行接口校验

  1. @Component 
  2. @Order(0) 
  3. @Slf4j 
  4. public class GatewayRequestFilter implements GlobalFilter { 
  5.  
  6.     @Override 
  7.     public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { 
  8.         //获取请求路径 
  9.         String rawPath = exchange.getRequest().getURI().getRawPath(); 
  10.  
  11.         if(isPv(rawPath)){ 
  12.             throw new HttpServerErrorException(HttpStatus.FORBIDDEN,"can't access private API"); 
  13.         } 
  14.         return chain.filter(newExchange); 
  15.     } 
  16.  
  17.      
  18.     private boolean isPv(String requestURI) { 
  19.         return isAccess(requestURI,"/pv"); 
  20.     } 
  21.  
  22.      
  23.     private boolean isAccess(String requestURI, String access) { 
  24.         //后端标准请求路径为 /访问控制/请求路径 
  25.         int index = requestURI.indexOf(access); 
  26.         return index >= 0 && StringUtils.countOccurrencesOf(requestURI.substring(0,index),"/") < 1; 
  27.     } 
  28.  

通过上面简单两步我们就能实现本文提出的问题了,接下来我们测试一下。

测试

直接访问后端服务,提示无法访问。

通过OrderService访问后端服务正常访问。

小结

让内部隐私接口不被外部访问,我相信做微服务开发的同学基本都会遇到。本文中提供的解决方案代码量很少而且接口路径规范可以根据自己的业务规则进行修改扩展,推荐大家使用。其实代码不是关键,关键在于要让团队共同遵守这个接口规范,思想比实现更重要。

 

来源:JAVA日知录内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯