一、 背景叙述
从公众号开始,小程序、移动应用、网站应用,到现在的视频号小店,微信提供很多种应用形态,让企业和个人开发者可以用适合的形式接入微信生态,满足自己的业务需求。
另外微信还提供第三方平台,为各行业的解决方案服务商提供了一个窗口,能够服务更多商家或中小企业个体接入微信生态,提升客户体验。
但无论是小程序、公众号还是第三方平台,依然只是在C端提供服务。无论是服务商还是企业个人开发者,想要通过上述形态接入微信生态,仍然离不开云端服务。
微信团队提供很优秀的开发和调试工具,单独做一个不联网的小程序,实现一些简单的功能,简单入门上手开发并不是很难。但如果是联网提供完整的带服务的小程序,对很多开发者来说就比较难了;更难的是另一个问:如何做一个稳定的、安全的后端服务?
2018年,微信联合腾讯云推出云开发,主要解决的是小程序后端服务的高门槛问题。但提供的云函数对传统开发模式的改造成本太大,灵活度不是很高。于是在2020年推出微信云托管,提供通用的容器服务,将服务构建环节交给开发者。
无论是云开发和云托管,最关键的并不是提供一个后端服务,而是提供后端服务的安全访问。所以可以看到,无论是云开发还是云托管,在微信应用(小程序、公众号服务)中提供的callFunction、callContainer方法,相比request方法本质上是提供了一个安全的访问入口。
云开发、云托管在一定程度上承担了运维和部署环节,使得其非常容易入门,对新手开发者很友好。但并不是所有开发者都是新手,很多成熟的开发者都有自己的一套成熟后端服务。如果为了接入微信的安全访问,而直接迁移自己的服务到云开发或云托管,阻力是相当大的。
另外云开发、云托管提供的是可独立存在的后端云服务,有独立的数据存储,使得其在调用方上挣脱不开同主体的限制,这也是服务商开发者使用起来最为难受的点。
所以有没有一种方案,让开发者既可以使用自己熟悉的后端服务基座,又可以非常灵活方便的接入微信的安全访问?
这就是新推出的Donut安全网关!
二、 什么是安全网关,有什么特色?
Donut安全网关提供了一个安全的接入链路,从调用端(小程序、公众号H5、APP、WEB)发起的请求直接进入微信环境接入层,微信接入层通过中转域名将请求转发至后端服务网络的「网关实例」中,在「网关实例」中通过路由配置将请求转发到开发者自己的上游业务服务,完成整个请求。
以上是整个链路的全景图,其中「网关实例」指的是部署在服务器或者是容器服务中的一套envoy网关(经过微信信息处理,有专属的证书加密)。
相比于云开发或云托管的访问链路,安全网关的链路是完全独立的,相对来说也更加成熟和安全。并且由于只做请求转发,不受同主体可用的限制。也就是说任何一个小程序或者公众号H5或其他形态应用,都可以使用安全网关链路实现请求。
当然,微信在链路中也提供了来源客户端的appid等标识,开发者可以在控制台或自己的后端服务针对的限制,防止其他未授权的客户端调用。
但是需要注意,安全网关并不是替代云开发或者云托管,安全网关可以与现在的云托管做深度融合,使得最终形态一定是对各类开发者均友好的。在云端服务领域还有很长的路程需要探索和精进!
三、 开始配置安全网关
1. 登录注册Donut平台
访问Donut控制台,使用微信扫码登录。
扫码完成后页面会自动跳转,进入控制台。首先先点击右上角头像,在列表中点击实名认证。
填入自己的姓名和身份证号码后,会弹出如下二维码,使用微信客户端扫码验证。
验证完成后会自动提示如下,此时就完成了实名认证流程。
2. 开通安全网关
在控制台页面点击安全网关的「立即开通」按钮
阅读服务协议并同意,开通完成!
页面会自动刷新,点击上方菜单栏「安全网关」,显示下述页面,开通流程完成。
3. 新建网关
在安全网关页面点击「新建网关」按钮,在弹出的对话框中填写网关名称,完成新建。一般网关以使用角度的应用维度区分,一般只需要一个即可,可以再创建一个用于规则测试。
在这里我填写的是app,大家可以按自己想法来填。
4. 安装网关实例
网关实例是一个经过处理过的envoy网关,主要作用就是接收微信侧发过来的请求,并按照自己设置做路由分发等流量管理。所以网关实例运行的服务器或者容器服务,应该具备以下几个条件:
- 有公网接入:可以是带公网IP的服务器,也可以是任何一个公网访问的容器服务[比如TKE、云托管等],如果服务器没有公网IP,可以在服务器的VPC网络中配置NAT网关,转发端口流量。
- 尽量靠近业务后端服务:网关实例最重要的作用就是路由分发,分发的上游服务可以用内网IP访问,也可以用私有域名访问;不推荐使用公网再发出去,会增加请求耗时。所以尽量与业务后端服务处于同一个私有网络,如果跨地域了,可以考虑对等连接,或者在不同地域配置多个网关实例(用域名解析来实现就近接入)
- 尽量避免与高峰值服务混在一起:虽然envoy本身对资源的消耗很小,但仍然需要注意不要与其他重资源消耗并可能引发宕机的服务部署在一起,否则将会导致网关实例不可用,从而影响请求顺利的转发。
一般根据自身的情况,有很多种方案可以选择。选择好实例所在位置后,根据环境不同,参照控制台给出的详细步骤,安装实例。目前有如下几种:
- Docker:如果你的服务器安装有Docker,这是最方便的。将镜像直接下载下来运行即可。
- Linux:适用于大多数情况。有很多系统版本,注意自己的系统版本不要出错。安装过程基本就是开管理员权限进入终端,然后安装curl、wget、jq(基本都有,如果没有就搜索一下linux怎么安装XXX),剩下的就是直接复制一把运行,如果有出错,可以先搜索引擎一下解决,实在不知道怎么解决,可以评论下来看看
- K8s:如果你的服务有运行于K8s运管的容器平台,可以用这个方法快速新建网关实例。最省心的方法!
在这里我使用一个服务器来执行安装过程,配置截图如下:
启动后进入root账号,执行命令如下:(最后一个是启动网关实例,可以使用nohup不挂断运行)
网关实例安装完毕后,控制台中点击「完成」按钮,进入下一步,可以在实例列表中看到已经安装在线的实例。
注意:
1. 在线情况下不可以从列表删除,需要先将网关下线,才可以从列表删除。
2. 默认的对外端口为9903,但根据自己配置也会有所不同,注意打印的port内容。
5. 发布网关配置
网关配置主要分为两部分:上游服务、路由配置。我们来分别配置。
5.1 上游服务
上游服务就是请求最终到达的地方,一般可以称为业务服务地址。可以是域名,也可以是IP地址。
在配置页点击「新建上游服务」按钮,弹出对话框,我们来填写一下。
- 上游服务名称:路由配置时用它来区分,一般言简意赅的单词即可,比如login_server。
- 备注:有时候英文不太容易记起具体是个什么,这里可以用中文长句描述一下给自己看。
- 协议:有HTTP和HTTPS,一般内网就HTTP,节省耗时,外网或者有安全需要的HTTPS
- 类型:分域名和IP,根据自己的情况来选择,一般选择IP。
- 域名:内网可以用私有DNS解析来配置域名,公网可以正常填写。
- IP:类型为IP时可见,IP可以填写公网IP;同属一个私有网络可以填写内部IP;如果跟网关实例同属于一个服务器,则可以填127.0.0.1。
在这里测试为了能让大家都能测试顺利并没有差异,直接填写一个mp官网的域名,后续可以根据自己的情况自己来变更。
注意:只在本测试中使用mp.weixin.qq.com,请不要在生产环境中尝试调用或恶意攻击操作。
5.2 路由配置
配置完上游服务后,会提示配置路由,点击即可跳转至路由配置页面的对话框
- 路由名称:清楚表示这个路由的作用即可,一般言简意赅的英文单词组合。
- 上游服务:拉取当前配置的服务列表,以上游服务名称为索引。
- 服务路径:就是访问时的路径,比如https://xx.com/api,想要匹配这个规则,路径就填写/api,如果没有路径就填 /
- 路径改写-可选:目前只支持静态改写,就是将匹配的服务路径改写为指定的路径,再传递给上游服务。比如上面说的 /api 进来,可以改写成 /interface 传递给上游。
- 请求限频-可选:配置这条路由的QPS值,流量防治的一种策略,默认是1000,范围是1-10000
- 准入域名-可选:发过来的请求会匹配请求头中的host值;如果配置则只接受此host发来的请求,一般在接入层有多个时但需要区分流量时使用。
在这里我们来配置一个测试用的路径,后面我们再配置更多来测试一下路由的能力。
5.3 发布配置
在控制台中反复配置的路由和上游服务,并不会影响实际线上的网关实例。我们在配置完成后,需要点击控制台的「发布配置」按钮,将配置上传至网关实例。此时网关实例才能够应用我们的最新配置。 ·
线上有了配置之后,我们就可以在右侧点击「线上网关配置」查看线上生效的配置情况
6. 配置接入层
接入层是在微信侧的概念。网关接入层承接并转发业务流量,具备分布式安全防护能力,支持就近接入弱网加速,同时集成微信安全风控能力。
通俗来讲,就是客户端在访问网关时,需要有一个地址,而这个地址就是接入层的一个节点。微信对每一个接入节点创建了一个专门的地址,用来接收客户端流量。
接入节点一般以客户端应用区分(比如A应用APP、B小程序,C网页WEB),或者应用矩阵区分(A应用多端APP、小程序、WEB),这样可以随时阻断或者转移流量。另外可以通过路由配置的准入域名,来实现不同应用的差异化转发;服务商第三方平台也可以利用此特性,来实现普通客户的应用承载,以及VIP客户的应用承载分流。
只有一个接入节点的域名地址也没有用,还需要我们配置一下进入到这里的请求流量转发到哪里。
在控制台中,点击「接入层」的「新建接入节点」按钮。
- 节点名称:一般以应用命名,言简意赅的英文单词组合即可。
- 备注:可以详细描述一下服务的应用是哪些,给自己备注一下。
- 访问方式:公网访问、小程序访问,可以根据自己的接入需要来选择,这会控制你的客户端请求的访问许可。
- APPID:当选择「小程序访问」时会出现,需要将允许访问的小程序appid填入,多个需要用,(英文逗号)隔开。
- 服务接入节点类型:域名、IP或云托管,就是网关实例应该以什么形式发现。如果就一个实例,则直接IP,域名一般用于IP容易变化的服务器或者容器服务,另外在多地域就近配置时使用也很不错,需要搭配DNS高级解析能力;云托管需要在空间管理TAB中绑定云托管所属账号,这个另外开一篇指引。
- 域名:填写域名,可以在公网指向网关实例所在的服务器,端口填写网关实例对外暴露的服务端口。
- IP:填写公网IP,能够指向网关实例所在的服务器,端口填写网关实例对外暴露的服务端口。
- 云托管:选择云托管环境-服务作为服务接入节点。
注意:
1. 多个接入层可以使用同一个网关实例,没有什么限制。一个接入层用多个实例,需要用域名来实现。
2. 需要注意配置安全规则,保证网关实例对外暴露的端口能够被公网访问。不要使用七层负载均衡来转发端口,可以使用NAT网关转发。
在这里配置的如下,IP自己注意替换一下
如果顺利完成不弹窗报错,则一切顺利,控制台可以看到节点。如果提示报错连接失败等,首先看下端口IP安全规则是否放开,注意是TCP协议。
7. 简单访问
上面步骤的接入域名为:https://a04fa8d0a-wx79c3e1e62f1acac0.preview.wxcloudrun.com
格式大概如下:https://${接入节点ID}-${Donut平台Appid}.preview.wxcloudrun.com
下面所有访问都请替换成自己的接入域名
我们在浏览器中访问域名时,效果应该如下:
当我们访问下面地址(替换自己的前缀),效果为:
https://xxx-wxxxx.preview.wxcloudrun.com/cgi-bin/scanloginqrcode?action=ask
也就是说,我们之前配置的路由,访问路径只是前缀匹配。
接下来我们新增一个配置,如下所示。记得「发布配置」线上生效。
当我们访问下面地址(替换自己的前缀)
https://xxx-wxxxx.preview.wxcloudrun.com/test?action=ask
会是404的提示。
接下来我们将一开始的index路由删掉,只保留api路由。
再次访问时会发现,页面为正常的返回了。
当我们再次将index路由配置回来,如下时:
一切都是可以的!
以上是一个路由优先级的实验,当流量转发过来时,会根据配置规则列表依次匹配,当匹配存在时立刻转发,匹配不存在时再向后匹配,直到匹配到或者匹配完为止。因此如果是/根路径,一般放置在路径最后,否则将直接从/转发走。
另外还有准入域名的实验,如果感兴趣我后面再补充。原理先在这里写一下:
准入域名一般填写的是接入域名或者是自定义域名,支持*通配符;当一个路由规则配置了准入域名A,则A的流量只会匹配这一个规则,其他未填写准入域名,或者准入域名不是一个优先级的路由规则根本不匹配。准入域名可以写如下格式:
- 准确域名,例:www.wx.com
- 后缀通配符,例:*.wx.com,*-wx.com
- 前缀通配符,例:wx.*,wx-*
- *不匹配空,比如*wx.com 将匹配 mpwx.com 而不匹配 wx.com
当一个域名打到了多个路由的准入域名,则优先级按最长的来。比如www.wx.qq.com 匹配 *.wx.qq.com ,而不是 *.wx.com
四、 在客户端中使用安全网关
目前可以在微信小程序中使用安全网关,使用步骤如下:
1. 准备环境
公测阶段,小程序调用安全网关需要开白名单,可以在申请页面填写问卷提交信息,通过后重新进入小程序,能够在基础库的列表最后,看到 develop 基础库,环境准备就完成了。
2. 获取接入节点ID
在安全网关控制台,转到「接入层」页面,将接入节点的默认域名取出,截取ID部分,如下图所示:
上图中,接入节点的ID为:a04fa8d0a-wx79c3e1e62f1acac0
这个ID需要替换成自己,每个人都不一样。
3. 配置请求域名
当前,网关的请求需要在mp后台配置request域名,直接将节点域名的完整地址填入就可以,协议为https,如下:
团队正在优化这个点,后面就不需要这个合法域名的配置了!
4. 编写请求代码
在这里我已经写了一个代码片段,可以直接导入到IDE
小程序端调用代码片段:https://developers.weixin.qq.com/s/D5lCBnmD77Ey
导入时需要注意使用第一步申请公测时填写的APPID,不要填写其他或者接口测试号,将不会显示 develop 基础库。
导入后,右上角点击「详情」按钮,在本地设置中,基础库选择develop
然后打开 app.js 文件,按下图所示,替换自己在第2步的接入节点ID
保存文件后,触发重新编译,在调试器console中可以看到网关请求打印的返回数据:
请求实际上有两个步骤,第一是网关的初始化,第二是call请求,在这里我对call请求做了简单的封装,并挂载在app下,大家也可以根据自己的需要封装。
请求的触发在 pages/index/index.js 中,代码片段中初始的是前面步骤简单访问时的页面
https://xxx-wxxxx.preview.wxcloudrun.com/test?action=ask
当method为GET时,data的数据将拼接成url参数,除了path之外,其他的大部分参数都遵循wx.request。所以可以参考这里。
当将上面的data参数去掉后,由于接口的特点会直接返回页面html内容而不是JSON字符串,所以会出现下述报错。
这是因为请求时传入datatype为json,会自动尝试对请求返回结果做json解析,如果不是json字符串,就会引起解析报错。可以直接将datatype改为text,如下图:
5. 上传体验版
公测期间,IDE内调试开发使用的是 develop 基础库,但是线上不会存在这种基础库,因此网关的调用代码需要跟随你的应用代码包一起上传。
在app.json中加入如下配置:
{
"cloud": true,
"cloudVersion": "alpha"
}
这样在你上传体验版时,网关的相关代码就随着你的代码一起打包上传了。
如果后面有一些新的特性,需要重新执行上传的步骤,其中的cloudVersion指的就是网关代码的版本,和你引入模块的版本管理形式相同,自己把握就行。
6. 降级重试
推荐大家有条件做一下降级策略,防止网关实例出现异常,或者接入层的规则出现问题,影响线上的用户调用。
先使用网关调用,网关调用失败时,使用wx.request再来一次。
异常情况下,返回的内容中有errCode,所以可以根据此来设置降级策略。
{
"data": {},
"statusCode": 404, // http状态码
"errMsg": "gateway.call:ok", // 请求正常则始终为 gateway.call:ok
"errCode": -651000, // 正常时无此属性。异常时会返回负值,代表云开发网关侧异常
"header": {
"date": "Wed, 19 May 2021 02:37:59 GMT",
"server": "envoy",
"content-length": "0"
},
"callID": "1665645158626-tsmg9Dpy"
}
上面代码片段里,在封装的方法中有预留降级的插入为止,大家根据自己的业务做一下改造就可以。
五、 其他补充
1、 网关实例9903是正式给微信接入层做请求转发用的,端口有证书校验,不需要担心这里的攻击问题。由于默认证书可能在多处用,你可以在控制台中生成一个专属的证书,直接在对应路径替换文件,然后重启一下实例。
2、 网关实例还有一个9902端口,是用来做路由测试的,你可以直接拼IP地址+9902端口,按照路由规则的路径测试,这个是不带证书校验的纯本地测试,也可以用于内网的流量转发,安全性不是很好,内网注意安全规则设置。
3、 网关实例还有一个19000端口,这个是管理控制台,所有人只要能访问到,就能把网关实例给停止了,还能读取你的所有配置,比较高危险了,不要裸露在外网,调试也尽量配置安全规则只允许你自己的IP访问。
4、网关实例已经启动了,但是没在控制台的列表里显示?先看下secret有没有填写正确,重新init一下;其次再看一下网络安全规则是否放通,在实例所在服务端ping一下xds.preview.wxcloudrun.com,或者telnet一下其80端口,如果不通需要放通。
5、当配置多个网络实例时,个别实例配置不更新还是旧的?重新启动一下实例基本能解决问题,或者19000控制台进入,看一下clusters和config_dump的信息是否和配置的描述相符,不相符控制台quitquitquit,然后重新运行启动命令。
6、当确认操作步骤正确,但是效果不符合预期时,可以将启动后的log日志完整截取复制,反馈到社区相关板块。docker启动执行 docker logs envoy;linux启动,将stdout或者nohup.out的内容截取复制。
7、如果代码片段打开切换develop基础库时,长时间不启动进入页面,调试器也没有输出,请耐心等待develop基础库下载完成,会有loading的动画加载。如果等待3min仍然不变化,重新启动IDE可解决。
点赞
Donut创建完企业空间后,作为小程序管理员的账号无法搜到名下绑定的小程序,只有公众号,请问这个要怎么绑定小程序呢
Donut 开发平台
iOS平台 测试版本 Bundle id: 怎么修改?
三连
学习
网关放腾讯云上后续能否走内网吗?