plugNmeet 2.5.3 REST API 调用指南

讲清 plugNmeet 2.5.3 管理 REST API 鉴权(API-KEY + HMAC-SHA256 双头)与调用方法:建房、签发入会 JWT、查询与结束房间全生命周期实测回显,附三类 401 错误码与排错方法。

plugNmeetWebRTC视频会议2026/10/26

plugNmeet 2.5.3 REST API 调用指南

目标:讲清 plugNmeet 2.5.3 管理 REST API 的鉴权机制(API-KEY + HMAC-SHA256 双头)与调用方法,实测建房、签发入会 JWT、查询房间、结束会议的完整生命周期,并给出三类鉴权失败的真实回显与排错方法。

一、环境信息

  • plugNmeet 服务端 v2.5.3(官方镜像部署,Web/API 端口 8145)
  • 调用端:Python 3.14 标准库(urllib.request,无需第三方依赖)
  • 凭证:API-KEY: APIkey1234567、SECRET: q1w2e3r4plugnmeetsecret0123456789abcd(取自 config.yaml 的 client.api_key/client.secret)
  • 实测时间:2026-10-26

🔗 服务部署与配置项出处见 《plugNmeet 2.5.3 Docker Compose 部署指南》、《plugNmeet 2.5.3 配置参数详解》;组件背景见 《plugNmeet 2.5.3 介绍与选型指南》。

二、鉴权机制

2.1 双请求头

所有 /auth/* 端点(源码路由组 auth := fiberApp.Group("/auth", ...HandleAuthHeaderCheck))要求两个自定义请求头:

头值说明
API-KEYconfig.yaml 的 client.api_key明文标识,先查存在性
HASH-SIGNATUREHMAC-SHA256(secret, 请求体原文) 的 hex 小写对请求体整体签名

两个规则实测验证:

  1. 签名密钥是 client.secret,不是 api_key;
  2. 签名输入是请求体的原始字节——签名用什么序列化,发送就必须原样发同一份字节。本文用 Python json.dumps(payload, separators=(",", ":"))(紧凑无空格)先签名再发送,保持一致即通过;若签名与发送内容序列化不一致,服务端验签必失败。

2.2 可复用调用函数

import hashlib
import hmac
import json
import urllib.request

BASE = "http://127.0.0.1:8145"          # 生产环境换成 https://你的域名
API_KEY = "APIkey1234567"
API_SECRET = "q1w2e3r4plugnmeetsecret0123456789abcd"

def call(path: str, payload: dict) -> dict:
    body = json.dumps(payload, separators=(",", ":"))          # 先定序列化
    sig = hmac.new(API_SECRET.encode(), body.encode(),
                   hashlib.sha256).hexdigest()                  # 对原文签名
    req = urllib.request.Request(
        BASE + path,
        data=body.encode(),                                     # 原样发送
        headers={
            "Content-Type": "application/json",
            "API-KEY": API_KEY,
            "HASH-SIGNATURE": sig,
        },
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=15) as resp:
        return json.loads(resp.read().decode())

2.3 鉴权失败回显(实测)

服务端对三种典型错误返回不同的 status_code,排错时直接对照:

场景HTTP响应体
签名错误(密钥不对/签名与体不一致)401{"status":false, "msg":"Failed to verify provided authentication details.", "status_code":"INVALID_TOKEN_OR_SIGNATURE"}
缺头401{"status":false, "msg":"Missing API-KEY header.", "status_code":"MISSING_REQUIRED_PARAMETER"}
API-KEY 不存在401{"status":false, "msg":"Invalid API key provided.", "status_code":"INVALID_API_KEY"}

三、端点总览

v2.5.3 的 /auth/* 管理面(源码 router.go 实录,全部 POST):

组端点用途
/auth/getClientFiles获取客户端静态资源路径
/auth/room/create创建房间(含完整房间元数据)
/getJoinToken为用户签发入会 JWT
/isRoomActive房间是否在会中
/getActiveRoomInfo单房间详情(含参与者)
/getActiveRoomsInfo全部活动房间列表
/endRoom结束房间
/fetchPastRooms分页查历史房间
/broadcastToRoom全房间广播自定义消息
/uploadWhiteboardFile上传白板文件
/createPoll创建投票
/auth/recording/fetch /info /updateMetadata /mergeRecordings /delete /getDownloadToken录制管理
/auth/analytics/fetch /delete /getDownloadToken会后分析
/auth/artifact/fetch /info /delete /getDownloadTokenAI 产物
/auth/recorder/notify录制器事件上报(录制组件专用)

另有两条平级体系:浏览器端 /api/*(入会 JWT 鉴权,会议内交互);BigBluebutton 兼容层 /{apiKey}/bigbluebutton/api/*(create/join/end 等全家桶,供已有 BBB 集成的第三方系统平迁)。

四、实战:完整生命周期实测

以下全部为对 2.5.3 实测环境真实调用的回显(响应 JSON 保留服务端原始格式,键后带空格)。

4.1 创建房间 /auth/room/create

请求体(room_id 必填;metadata.room_features 是 v2.5.3 的房间能力集):

{"room_id":"demo-room-01","metadata":{"room_title":"演示房间","welcome_message":"欢迎加入 plugNmeet 2.5.3 演示会议","room_features":{"allow_webcams":true,"mute_on_start":false,"allow_self_permission":true,"admin_only_webcams":false,"allow_view_other_webcams":true,"allow_view_other_participants":true,"allow_polls":true,"connection_quality_calculator":false,"allow_rtmp":false,"allow_recording":false,"allow_virtual_background":false,"external_media_player":false,"quiz":false,"chat_features":{"allow_chat":true,"allow_file_upload":true,"allow_chat_reactions":true},"shared_note_pad_features":{"allowed_shared_note_pad":true},"whiteboard_features":{"allowed_whiteboard":true},"speak_request_features":{"allow_speak_request":true}}}}

响应(截取,服务端会回填全部默认能力):

{"status":true, "msg":"success", "status_code":"SUCCESS", "room_info":{"room_title":"演示房间", "room_id":"demo-room-01", "sid":"e4356362-b1cf-4c49-914a-907defb450e1", "joined_participants":"0", "is_running":1, "is_recording":0, "is_active_rtmp":0, "webhook_url":"", "is_breakout_room":0, "parent_room_id":"", "creation_time":"1793010994", "metadata":"{...完整JSON字符串...}"}}

实测要点:

  • 字段级校验:metadata.room_features 缺失时 2.5.3 直接拒绝并返回 protovalidate 的字段错误明细(本实验首次调用即遇到),建房请求需带完整 room_features 结构。
  • 请求字段与响应字段并非一一映射:实测请求里发 chat_features.allow_chat:true,服务端回显是 "chat_features":{"is_allow":false, "is_allow_file_upload":false, "allowed_file_types":[]}——能力集内部是「is_allow 允许 / is_active 激活」两级开关模型,且部分请求字段名与响应字段名不同。以服务端回显为准核对能力状态,不要假设请求字段会原样落回。
  • sid 是房间在 LiveKit 侧的会话 ID;creation_time 为 Unix 秒。

4.2 签发入会 Token /auth/room/getJoinToken

请求体:

{"room_id":"demo-room-01","user_info":{"name":"admin","user_id":"user-admin-001","is_admin":true,"hidden":false}}

响应(token 为标准 JWT):

{"status":true, "msg":"success", "status_code":"SUCCESS", "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTMwMTMzMjQsImlzX2FkbWluIjp0cnVlLCJpc3MiOiJBUElrZXkxMjM0NTY3IiwibmFtZSI6ImFkbWluIiwibmJmIjoxNzkzMDEyNzI0LCJyb29tX2lkIjoiZGVtby1yb29tLTAxIiwic3ViIjoidXNlci1hZG1pbi0wMDEiLCJ1c2VyX2lkIjoidXNlci1hZG1pbi0wMDEifQ.09AvIsKccoQkQqRsVsdu5jTPW9lL5advxAJ9pFRwGsA"}

解码后的 JWT 结构(实测):

// header
{"alg": "HS256", "typ": "JWT"}
// payload
{"exp": 1793013324, "is_admin": true, "iss": "APIkey1234567", "name": "admin", "nbf": 1793012724, "room_id": "demo-room-01", "sub": "user-admin-001", "user_id": "user-admin-001"}
  • iss 即 client.api_key;exp-nbf = 600 秒,对应 config.yaml 的 token_validity: 10m(客户端会自动续期)。
  • 签名密钥是 client.secret(与 API 鉴权同一把),拿到 token 即可入会,务必走 HTTPS 下发。
  • 入会 URL:https://<域名>/?access_token=<token>。

4.3 查询房间

单房间(含 participants_info 实时成员列表):

// POST /auth/room/getActiveRoomInfo  {"room_id":"demo-room-01"}
{"status":true, "msg":"success", "status_code":"SUCCESS", "room":{"room_info":{...}, "participants_info":[]}}

活动房间列表:

// POST /auth/room/getActiveRoomsInfo  {}
{"status":true, "msg":"success", "status_code":"SUCCESS", "rooms":[{"room_info":{...}, "participants_info":[]}]}

注意空态语义(实测):无活动房间时返回 {"status":false, "msg":"no active room found", "status_code":"NOT_FOUND", "rooms":[]}——HTTP 仍是 200,rooms 为空数组且 status:false,业务代码要按 rooms 数组判空而不是 status 布尔。

4.4 房间在会判定与结束(闭环实测)

// POST /auth/room/isRoomActive  {"room_id":"demo-room-01"}
{"status":true, "msg":"room is active", "status_code":"SUCCESS", "is_active":true}

// POST /auth/room/endRoom  {"room_id":"demo-room-01"}
{"status":true, "msg":"success", "status_code":"SUCCESS"}

实测发现 endRoom 是异步关闭:返回 success 后立刻再查 isRoomActive 仍可能拿到 is_active:true(房间状态清理经 NATS 广播、依赖组件逐个退出),本次实测约 6 秒后状态才落定:

// 数秒后再查
{"status":true, "msg":"room not found", "status_code":"ROOM_NOT_FOUND", "is_active":false}
{"status":false, "msg":"no active room found", "status_code":"NOT_FOUND", "rooms":[]}

集成方注意:结束房间后不要立即同步查询并断言,应轮询直到 is_active:false/ROOM_NOT_FOUND;关闭过渡期对同一房间重复 endRoom 还可能等到请求超时(实测现象),属正常竞态。

五、错误码速查(/auth 面)

status_code含义处置
SUCCESS成功—
INVALID_TOKEN_OR_SIGNATURE验签失败核对 secret 与签名输入=请求体原文
MISSING_REQUIRED_PARAMETER缺 API-KEY 头补双头
INVALID_API_KEYkey 不存在核对 api_key
NOT_FOUND资源不存在(含空列表)判空处理
ROOM_NOT_FOUND房间不存在/已结束先 create 再操作
字段校验明细请求结构不符按返回的 protovalidate 提示补字段

六、SDK 与生态兼容

  • 官方 SDK:PHP(mynaparrot/plugnmeet-sdk-php,Composer)与 JavaScript(plugnmeet-sdk,npm),封装了双头签名与全部 /auth 端点。
  • 社区 SDK:Python 有社区维护版本;本文直接用标准库演示签名细节,便于排查 SDK 之外的自定义集成。
  • BBB 兼容:GET/POST {BASE}/{apiKey}/bigbluebutton/api/create|join|end|...,校验串规则与 BBB 一致(sha1(checksum)),已有 BBB 集成的系统改 baseURL 即可平迁,bbb_join_host 配置项控制外发 join URL 域名。

七、常见问题

  1. 401 INVALID_TOKEN_OR_SIGNATURE 但头都带了:签名输入与发送体不一致(序列化差异)。签名与发送用同一份字节;Content-Type 必须是 application/json。
  2. create 返回字段校验错误:v2.5.3 强校验 metadata.room_features,从 4.1 节请求体起步再按需增改。
  3. 发送的 feature 开关没生效:能力集是 is_allow/is_active 两级模型且部分字段名与请求不同,以 getActiveRoomInfo 回显为准核对。
  4. endRoom 后查询仍 active:异步关闭未完成,轮询数秒(实测约 6 秒)。
  5. rooms:[] 但 HTTP 200:空态返回 status:false + NOT_FOUND,按数组判空。
  6. token 拿到但进不了会:token 绑定 room_id 且 10 分钟有效(exp-nbf);房间需在会中(is_running:1),过期重新调 getJoinToken。

八、参考链接