# 小程序环境共享

> 版本要求：开发者工具 >= `1.03.2009140` （[稳定版下载](/miniprogram/dev/server/API/mp-access-token/api_getstableaccesstoken.md)）

云开发支持跨账号环境（资源）共享，即一个小程序的云开发资源可以授权共享给同主体下其他小程序 / 公众号使用，并有以下好处：

| 优势 & 特点 | 说明 |
| :--- | :--- |
| **资源复用**  |  云开发资源可共享给其他账号使用，创建新小程序无需复制或迁移数据  |
| **能力复用**  |  开发好的云函数可以授权给其他账号原生调用，类似 HTTP 服务，做到能力复用  |
| **Web 支持**   |  在 Web 中既可以[使用公众号登录态访问微信云开发资源和能力](/minigame/dev/wxcloud/basis/web)，又可以在 Web 中用[未登录模式](/minigame/dev/wxcloud/basis/identityless)访问  |
| **细粒度授权**   |  授权粒度细，如可以只授权云函数调用权限而不授权修改权限  |
| **单层级授权**   |  单层级授权保证了安全，如 A 有 B 的授权，B 有 C 的授权，但 A 没有 C 的授权，此时 A 可以调 B 但不能直接调 C  |

## 小程序间跨账号资源共享

### 操作步骤

1.开通，使用 `1.03.2009140` 或以上版本的开发者工具，进入云控制台，到 「设置 - 拓展能力 - 环境共享」 点击开通即开通环境共享能力。

![](https://res.wx.qq.com/op_res/ciR22tbdpwZ0p7nHsXTUjScoh_60UWG1rkOQLlD5PdYcPEUX8Dci8FbcyXjZMOsU)

2.共享，环境共享开通后将在顶部 tab 显示环境共享功能，进入 「环境共享」 的页面，点击「添加共享」，即可授权**同主体下**其他小程序/公众号使用当前小程序下的云开发资源。

![](https://res.wx.qq.com/op_res/R3qZESZZ1WQAnfnKgvECJm9sy7SsB9Gw-gxOcVLiFmDQ_yc0ywdwJVmWWKyqV3hR)

3.授权，选择共享的云环境，默认选中所有环境操作权限，可根据实际使用场景自定义授权。授权只可授权当前小程序的自有环境，如 A 有 B 授权的环境，A 不可将 B 授权的环境再次授权给 C；

![](https://res.wx.qq.com/op_res/mSzTqOrW8LOWJox1uqaNJK-mRkXE9jJlh2hNqt5ruA6lM1crcGdG2ihDmuCf8_uG)

4.被共享环境的小程序使用，使用 `1.03.2009140` 或以上版本的开发者工具，进入云控制台，点击「环境共享」进入「环境共享」页面可查看被共享小程序情况；如需在云控制台查看授权环境的资源情况，可前往「设置-环境名称」将环境切换至该授权环境即可，同时在被授权操作的情况下可以对授权环境进行操作。

![](https://res.wx.qq.com/op_res/LxDYbhPUX_LNJLWjvcOUc2oR5mZiLGvpwZacBfmkNQqNuzv1tTUOktE4plhBtdjZ)

### cloudbase_auth 云函数

在使用共享环境之前，需要保证资源方拥有 `cloudbase_auth` 云函数，用于鉴权调用方的身份并制定相关权限。

在调用方 `cloud.init()` 的过程中，会**首先执行**这个函数，如果这个函数不存在，会提示找不到对应的`FunctionName`。请务必参考示例在资源方添加此函数。

被调的资源方小程序 cloudbase_auth 云函数简易示例：

```js
const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()

  console.log(event)
  console.log(wxContext)
  // 跨账号调用时，由此拿到来源方小程序/公众号 AppID
  console.log(wxContext.FROM_APPID)
  // 跨账号调用时，由此拿到来源方小程序/公众号的用户 OpenID
  console.log(wxContext.FROM_OPENID)
  // 跨账号调用、且满足 unionid 获取条件时，由此拿到同主体下的用户 UnionID
  console.log(wxContext.FROM_UNIONID)

  return {
    errCode: 0,
    errMsg: '',
    auth: JSON.stringify({
      // 自定义安全规则
      // 在前端访问资源方数据库、云函数等资源时，资源方可以通过
      // 安全规则的 `auth.custom` 字段获取此对象的内容做校验，
      // 像这个示例就是资源方可以在安全规则中通过 `auth.custom.x` 获取
      x: 1,
    }),
  }
}
```

**cloudbase_auth 云函数交互协议说明**

`cloudbase_auth` 云函数返回的对象结构协议：

| 属性 | 类型 | 默认值 | 必填 | 说明 |
| :---- | :---- | :------ | :-------- | :---- |
| errCode | number |  | 是 | 自定义错误码，0 表示授权通过，非 0 表示拒绝授权，会透传回给调用方 |
| errMsg | string |  | 否 | 自定义错误信息，errCode 非 0 时透传回给调用方 |
| auth | string |  | 否 | 安全规则对象，必须序列化成字符串 |

### 代码使用

小程序代码使用示例（需小程序公共库 `2.13.0` 或以上）：

```js
// 声明新的 cloud 实例
var c1 = new wx.cloud.Cloud({
  // 资源方 AppID
  resourceAppid: 'wxe0e2656d74f0bff3',
  // 资源方环境 ID
  resourceEnv: '环境ID',
})

// 跨账号调用，必须等待 init 完成
// init 过程中，资源方小程序对应环境下的 cloudbase_auth 函数会被调用，并需返回协议字段（见下）来确认允许访问、并可自定义安全规则
await c1.init()

// 完成后正常使用资源方的已授权的云资源
await c1.callFunction({
  name: '函数名',
  data: {},
})
```

在云函数中使用与在小程序中并没有多少区别（需 `wx-server-sdk` 版本大于或等于 `2.3.0`）：

```js
const cloud = require('wx-server-sdk')

exports.main = async (event) => {
  // 声明新的 cloud 实例
  var c1 = new cloud.Cloud({
    // 资源方 AppID
    resourceAppid: 'wxe0e2656d74f0bff3',
    // 资源方环境 ID
    resourceEnv: '环境ID',
  })

  // 跨账号调用，必须等待 init 完成
  // init 过程中，资源方小程序对应环境下的 cloudbase_auth 函数会被调用，并需返回协议字段（见下）来确认允许访问、并可自定义安全规则
  await c1.init()

  // 完成后正常使用资源方的已授权的云资源
  return c1.callFunction({
    name: '函数名',
    data: {},
  })
}
```

如果有些云调用能力，需要指定发起方 appid，可以在云调用之前传入调用方 `appid`

cloud 正常形式

``` js
const cloud = require('wx-server-sdk')

exports.main = async (event) => {
  // 初始化
  cloud.init({
    env: cloud.DYNAMIC_CURRENT_ENV
  })

  // 使用使用方小程序（非资源方）身份发起支付
  return cloud.cloudPay({ appid: '发起支付的小程序appid' }).unifiedOrder({
    "body" : "小秋TIT店-超市", // 商品描述
    "outTradeNo" : "1217752501201407033233368018", // 商户订单号
    "spbillCreateIp" : "请传入终端 ip 地址，支持 ipv6", // 终端 IP
    "subMchId" : "1900009231", // 商户号
    "totalFee" : 1, // 总金额
    "envId": "环境ID", // 云函数环境名称
    "functionName": "pay_cb" // 支付结果通知回调云函数名
  })
}
```

实例调用形式

``` js
const cloud = require('wx-server-sdk')

exports.main = async (event) => {
  // 声明新的 cloud 实例
  var c1 = new cloud.Cloud({
    // 资源方 AppID
    resourceAppid: 'wxe0e2656d74f0bff3',
    // 资源方环境 ID
    resourceEnv: '环境ID',
  })

  // 跨账号调用，必须等待 init 完成
  // init 过程中，资源方小程序对应环境下的 cloudbase_auth 函数会被调用，并需返回协议字段（见下）来确认允许访问、并可自定义安全规则
  await c1.init()

  // 完成后正常使用资源方的已授权的云资源，
  return c1.cloudPay({ appid: '发起支付的小程序appid' }).unifiedOrder({
    "body" : "小秋TIT店-超市", // 商品描述
    "outTradeNo" : "1217752501201407033233368018", // 商户订单号
    "spbillCreateIp" : "请传入终端 ip 地址，支持 ipv6", // 终端 IP
    "subMchId" : "1900009231", // 商户号
    "totalFee" : 1, // 总金额
    "envId": "环境ID", // 云函数环境名称
    "functionName": "pay_cb" // 支付结果通知回调云函数名
  })
}
```

### 环境共享给未开通云开发的小程序

1）未开通云开发的小程序无法进入云开发控制台，如被同主体的其他小程序共享环境后，默认允许未开通云开发的小程序可进入云开发控制台，且默认开通「环境共享」功能；进入控制台后默认显示授权共享环境的第一个小程序的云开发环境。

2）未开通云开发的小程序被共享后，如需开通云开发，则可通过路径「设置-切换环境-创建环境」开通云开发并创建环境；

3）未开通云开发的小程序被共享后，解除所有小程序的共享关系，则环境共享功能注销，且云开发控制台入口消失；
