Sign inGet started

终止成员连接

频道授权控制订阅,但不会分配连接级别的身份。没有该身份,在其他地方退出登录不会关闭已有的 socket 或移除其频道订阅。
调用 signin() 从后端为连接分配一个 member_id。之后断开连接操作就可以关闭该成员在应用上持有的所有连接。
在远程退出登录、令牌撤销、封禁、密码更改或工作区席位移除后使用此流程。

1. 为连接签入身份

将客户端指向你自己后端的一个端点,然后调用一次 signin()
import { BirdRealtime } from "@messagebird/realtime";

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

const member = await bird.signin();
console.log("signed in as", member.member_id);
身份属于连接。调用一次 signin(),客户端会在每次重连后重新签入。
签入不会授权频道订阅。私有频道和 presence 频道仍然会调用你的频道授权端点。没有成员身份的连接可以订阅该端点批准的任何频道。参见频道授权

2. 从后端签署身份

客户端通过 POST 请求发送连接 ID:
代码示例
{ "connection_id": "26896.319537" }
你的端点以 JSON 字符串形式返回身份,加上对该字符串的签名:
代码示例
{
  "auth": "your-app-key:8f9a…",
  "member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}
待签名的字符串是 <connection_id>::member::<member_data>member 两侧各有两个冒号。用应用密钥对其进行 HMAC-SHA256 运算,十六进制编码,并加上应用 key 前缀:
import { createHmac } from "node:crypto";

app.post("/bird/auth/member", (req, res) => {
  const { connection_id } = req.body;

  // Your own decision: who is this caller, and may they connect at all?
  const user = getUserFromSession(req);
  if (!user) return res.sendStatus(403);

  const memberData = JSON.stringify({
    member_id: user.id,
    member_info: { name: user.name },
  });
  const sig = createHmac("sha256", process.env.BIRD_REALTIME_SECRET)
    .update(`${connection_id}::member::${memberData}`)
    .digest("hex");

  res.json({ auth: `${process.env.BIRD_REALTIME_KEY}:${sig}`, member_data: memberData });
});
对你返回的 member_data 字符串原样签名。重新序列化对象可能改变其字节并使签名失效。
member_id 是断开连接操作的目标值。它接受最多 128 个 URL 安全字符,包括 + : @ . _ -,但不包括 / ? # % 或空白字符。如果你的标识符包含不支持的字符,请在签名前将其映射为稳定的安全值。边缘节点会拒绝无效的成员 ID,使连接没有可被断开连接操作定位的身份。
member_info 是可选的。在连接签入时,它返回给该客户端,而不是广播到 presence 频道。
身份还可以携带一个 watchlist 成员 ID 数组。在启用了 watchlist_events 的应用上,连接会在这些成员上线或下线时收到通知;参见监视列表事件
此处签名的字符串与 presence 订阅签名的字符串故意不同,因此 presence 授权永远无法被重放来冒领身份,即使两种载荷都叫做 member_data

3. 断开成员连接

await bird.realtime.members.disconnect("rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42");
该操作会关闭该成员在应用上的所有已签入连接,包括其他标签页和设备。它不会关闭匿名连接或分配给其他成员的连接。

客户端看到的情况

连接以代码 4009 关闭,且不会自动重连:
bird.connection.bind("error", (e) => {
  if (e.code === 4009) showSignedOutScreen();
});
认证结束后显示已退出状态。调用 bird.connect() 会启动一个新连接并通过你的端点签入,因此只在成员的授权状态发生变化后才重连。
签入失败不会关闭 socket。客户端会单独报告失败,并使连接保持无成员身份状态。重连后,客户端通过 signin_error 报告此情况,因为原始的 signin() promise 已经 resolve。
bird.connection.bind("signin_error", (e) => {
  console.warn("connection has no identity:", e.message);
});
连接仍然可以接收已授权频道的事件,但成员事件和断开连接操作无法定位它。在浏览器客户端中,此状态下 bird.signedInMembernull

阻止重连

断开连接操作关闭当前连接,但不会创建持久性阻止。同一客户端可以再次连接。
在断开成员连接之前撤销会话或记录封禁。这样,如果客户端重连,你的成员授权端点可以返回 403 Forbidden

后续步骤