查看原文
其他

面试官:业务开发时,接口不能对外暴露怎么办?


推荐关注

扫码关注“后端架构师”,选择“星标”公众号

重磅干货,第一时间送达!

责编:架构君 | 来源:码猿技术专栏


上一篇好文:一款强大的代码生成器让前端和后台代码一键生成,不需要写任何代码!


大家好,我是后端架构师。


在业务开发的时候,经常会遇到某一个接口不能对外暴露,只能内网服务间调用的实际需求。面对这样的情况,我们该如何实现呢?今天,我们就来理一理这个问题,从几个可行的方案中,挑选一个来实现。

1.内外网接口微服务隔离

将对外暴露的接口和对内暴露的接口分别放到两个微服务上,一个服务里所有的接口均对外暴露,另一个服务的接口只能内网服务间调用。

该方案需要额外编写一个只对内部暴露接口的微服务,将所有只能对内暴露的业务接口聚合到这个微服务里,通过这个聚合的微服务,分别去各个业务侧获取资源。

该方案,新增一个微服务做请求转发,增加了系统的复杂性,增大了调用耗时以及后期的维护成本。

2.网关 + redis 实现白名单机制

在 redis 里维护一套接口白名单列表,外部请求到达网关时,从 redis 获取接口白名单,在白名单内的接口放行,反之拒绝掉。

该方案的好处是,对业务代码零侵入,只需要维护好白名单列表即可;

不足之处在于,白名单的维护是一个持续性投入的工作,在很多公司,业务开发无法直接触及到 redis,只能提工单申请,增加了开发成本;另外,每次请求进来,都需要判断白名单,增加了系统响应耗时,考虑到正常情况下外部进来的请求大部分都是在白名单内的,只有极少数恶意请求才会被白名单机制所拦截,所以该方案的性价比很低。

3.方案三 网关 + AOP

相比于方案二对接口进行白名单判断而言,方案三是对请求来源进行判断,并将该判断下沉到业务侧。避免了网关侧的逻辑判断,从而提升系统响应速度。

牛逼啊!接私活必备的 N 个开源项目!赶快收藏

我们知道,外部进来的请求一定会经过网关再被分发到具体的业务侧,内部服务间的调用是不用走外部网关的(走 k8s 的 service)。

根据这个特点,我们可以对所有经过网关的请求的header里添加一个字段,业务侧接口收到请求后,判断header里是否有该字段,如果有,则说明该请求来自外部,没有,则属于内部服务的调用,再根据该接口是否属于内部接口来决定是否放行该请求。

该方案将内外网访问权限的处理分布到各个业务侧进行,消除了由网关来处理的系统性瓶颈;同时,开发者可以在业务侧直接确定接口的内外网访问权限,提升开发效率的同时,增加了代码的可读性。

当然该方案会对业务代码有一定的侵入性,不过可以通过注解的形式,最大限度的降低这种侵入性。


具体实操


下面就方案三,进行具体的代码演示。

首先在网关侧,需要对进来的请求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""").header("from""public").build())  
         .build()  
         );  
    }  
  
    @Override  
    public int getOrder () {  
        return 0;  
    }  
 }  

接着,编写内外网访问权限判断的AOP和注解

@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 {  
}  

最后,在只能内网访问的接口上加上@OnlyIntranetAccess注解即可

@GetMapping ( "/role/add" )  
@OnlyIntranetAccess  
public String onlyIntranetAccess() {  
    return "该接口只允许内部服务调用";  
}


欢迎有需要的同学试试,如果本文对您有帮助,也请帮忙点个 赞 + 在看 啦!❤️

在 GitHub猿 还有更多优质项目系统学习资源,欢迎分享给其他同学吧!

PS:如果觉得我的分享不错,欢迎大家随手点赞、转发、在看。


最后给读者整理了一份BAT大厂面试真题,需要的可扫码加微信备注:“面试”获取。


版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

END

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结。

别找了,想获取史上最全的Java大厂面试题学习资料

扫下方二维码回复「面试」就好了

历史好文:

比特币又爆了。。。

分享一个牛逼的开源后台管理系统,不要造轮子了(附源码)!

基于SpringBoot 的CMS系统,拿去开发企业官网真香

10w 行级别数据的 Excel 导入优化记录

面试官:MySQL 批量插入,如何不插入重复数据?

写代码爬取了某 Hub 资源,只为撸这个鉴黄平台!

如何搭建一台永久运行的个人服务器?

做一个不崩溃的核酸系统有多难?

这个外包公司太恶心了。。进去请三思!

分库分表后路由策略设计

国庆回家,同学聚会程序员的尴尬

SQL优化 21 连击,建议收藏!

不好意思, Maven 该换了!

优秀的代码都是如何分层的?

扫码关注“后端架构师”,选择“星标”公众号

重磅干货,第一时间送达!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存