Sign inGet started

频道授权

任何持有 app key 的客户端都可以订阅公共频道。有两个频道名前缀要求你的后端对订阅进行授权。你无需单独配置频道。
名为 private-… 的频道要求你的后端批准每次订阅。名为 presence-… 的频道同样如此,并且还会为订阅者附加身份标识,使频道上的所有人都能看到其他成员。其他名称的频道均为公共频道。
只有你的后端持有 app secret。客户端请求你的服务器为特定订阅签名,Realtime 边缘节点在接受订阅前验证该签名。你的服务器在不向客户端暴露 secret 的情况下决定调用方是否可以订阅。

将客户端指向你的端点

在你自己的后端为客户端提供一个 authEndpoint
import { BirdRealtime } from "@messagebird/realtime";

const bird = new BirdRealtime({
  appKey: "your-app-key",
  region: "us1",
  authEndpoint: "/bird/auth",
});

const room = bird.subscribe("presence-room-1");
客户端会在每次 private 或 presence 订阅时调用此端点,包括重连后恢复的订阅。授权仅适用于单个连接,因为签名中包含了该连接的 connection ID。
浏览器客户端默认要求同源端点。设置 allowCrossOriginAuth: true 可使用跨域 authEndpoint。浏览器客户端仅向同源端点发送已配置的 authHeaders

端点的接收与返回

客户端 POST JSON:
代码示例
{ "connection_id": "26896.319537", "channel_name": "presence-room-1" }
返回签名:
代码示例
{ "auth": "your-app-key:8f9a…" }
对于 presence 频道,还需以 JSON 字符串形式返回成员身份标识,即你签名的同一个字符串:
代码示例
{
  "auth": "your-app-key:8f9a…",
  "member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}
member_id 是其他成员看到的身份标识,也是断开连接操作所针对的值。member_info 是可选的 JSON 数据,会分发给频道中的每位成员。它有 1 KB 的大小限制,因此只应包含少量、非敏感的个人资料数据。
在此端点中使用调用方的 session cookie 或 bearer token 对其进行授权。当调用方不得加入频道时返回 403 Forbidden。对于 presence 频道,在同一响应中分配身份标识。

签名字符串

用冒号拼接,然后使用 app secret 进行 HMAC-SHA256 运算并十六进制编码。在结果前加上 app key 和一个冒号作为前缀。
频道类型签名字符串
private-…<connection_id>:<channel_name>
private-encrypted-…<connection_id>:<channel_name>
presence-…<connection_id>:<channel_name>:<member_data>
对于 presence 频道,签名时使用你返回的完全相同的 member_data 字符串。重新序列化同一对象可能改变键顺序或空格,导致签名失效。
加密频道的签名方式与 private 频道相同,其授权响应还会以 shared_secret 返回频道的解密密钥。SDK 辅助方法会自动添加该密钥;加密频道详细介绍了密钥派生和频道行为。
每个服务端 SDK 都提供一个 authorizeChannel 辅助方法。它使用已配置的 app 凭据进行签名并返回响应体,无需发起网络请求。对于加密频道,该辅助方法还会添加 shared_secret
app.post("/bird/auth", async (req, res) => {
  const { connection_id, channel_name } = req.body;

  // Your own authorization decision goes here.
  const user = getUserFromSession(req);
  if (!user || !mayJoin(user, channel_name)) return res.sendStatus(403);

  const memberData = channel_name.startsWith("presence-")
    ? JSON.stringify({ member_id: user.id, member_info: { name: user.name } })
    : undefined;

  res.json(
    await bird.realtime.authorizeChannel({
      connectionId: connection_id,
      channelName: channel_name,
      memberData,
    }),
  );
});
在没有 SDK 的语言中,签名契约是相同的:使用 app secret 对字符串进行 HMAC-SHA256 运算,十六进制编码,然后在结果前加上 app key 和一个冒号。

成员与连接

成员是一个身份标识,而连接是一个打开的 WebSocket。如果某人在三个标签页中打开你的应用,则一个成员持有三个连接。member_added 在第一个连接订阅时触发,member_removed 在最后一个连接离开时触发。其他连接的变化会改变频道的连接计数,但不会产生成员事件。

常见故障

被拒绝的订阅会以客户端错误的形式到达。检查以下常见原因:
  • 签名无效。 你签名的字符串不匹配。几乎总是因为重新序列化了 member_data,或者签名时使用的频道名缺少 private-presence- 前缀。
  • 密钥无效。auth 中的密钥属于另一个应用,或已被撤销。轮换密钥意味着需要同时更新客户端的 appKey 和端点签名所用的 secret。
  • 缺少成员数据。 收到的 presence 订阅未包含 member_data。Presence 频道不允许匿名加入。
  • 来自你自己端点的 403 你的授权逻辑拒绝了请求,这对于不允许加入的用户来说是预期行为。

后续步骤

  • 发送你的第一个实时事件是本指南所基于的端到端演练。
  • 加密频道在此签名的基础上,还会向已批准的订阅者分发解密密钥。
  • Presence 频道涵盖成员列表、成员事件以及从服务端读取在线状态。
  • 终止成员连接是你的后端计算的另一个签名,它允许你关闭某个成员的所有连接。
  • Webhooks 与事件介绍了 realtime.* 事件,包括成员加入和离开等事件在你自己端点上的处理。

相关资源

继续查阅此主题的文档、指南和示例。资源为英文。

动手实践并获取实施简报