Discuz! X5.0 RESTful API 发帖打通:两种认证模式与 script 格式问题

本文摘要背景Discuz! X5.0 论坛原生自带 RESTful API,支持通过 OAuth2.0 风格签名认证进行发帖、回帖、版块管理等操作。目标是把 Typecho 博客文章自动同步发布到 Discuz! 论坛,实现内容的多端分发。本文记录 RESTful API 的两种认证模式、实测结论,以及新版标准模式下遇到的认证与脚本分发问题及根因。过程问题描述论坛部署于 www.example.com(D...

Discuz! X5.0 RESTful API 发帖打通封面

背景

Discuz! X5.0 论坛原生自带 RESTful API,支持通过 OAuth2.0 风格签名认证进行发帖、回帖、版块管理等操作。目标是把 Typecho 博客文章自动同步发布到 Discuz! 论坛,实现内容的多端分发。本文记录 RESTful API 的两种认证模式、实测结论,以及新版标准模式下遇到的认证与脚本分发问题及根因。

过程

问题描述

论坛部署于 www.example.com(Discuz! X5.0,内测中),需要拿到一套稳定的 API 调用方式,能完成「创建帖子 → 上传附件 → 创建版块」等操作。Discuz! X5.0 的 RESTful API 入口在 /api/restful/index.php,支持两套认证机制。

两种认证模式

模式一:旧模式(appid + secret 放在查询参数)

直接在 URL query 里携带 appidsecret,例如:

/api/restful/index.php?appid=<appid>&secret=<secret>&url=/forum/thread/list/

实测该模式下大量接口均可用(已验证全通过):

模块接口
forumthread/list、thread/create、thread/update、thread/delete、post/list、post/create、post/update、post/delete、forum/list、forum/create、forum/update、forum/delete、attachment/list、attachment/create
memberregister、login、logout、profile、update、delete
其他group/list、site/setting、site/check、portal/list、portal/article/list、follow/list、follow/create、follow/delete
细节一:旧模式 URL 末尾必须带斜杠(如 /forum/thread/list/),否则会被重定向到 /admin.php

模式二:新版标准 OAuth2.0(header 签名)

通过请求头携带认证信息,签名算法为:

sign = base64( sha256_hex( nonce + t + secret ) )

其中 nonce 为随机字符串,t 为当前 Unix 时间戳。请求头为:AppidNonceTSign。先取 token:

GET /api/restful/index.php?/token
Headers: Appid, Nonce, T, Sign

成功返回 {"ret":0,"token":"..."}。取到 token 后,后续业务请求额外携带 Token 头。

细节二:PHP 的 hash('sha256',...) 默认返回十六进制字符串,因此签名时需先对 hex digest 做 base64,而不是直接对原始串做 base64。

卡点与排查

新版认证里,token 获取可以成功,但业务接口调用出现三类报错:

  • -118 scriptCheck: script format is error
  • -114 initParam: api is invalid
  • -101 checkSign: param is missing(改用旧模式 query 参数时,说明该认证只认 header、不认 query)

逐一排查后发现,接口定义数据(存在 Redis,key 形如 rApi_/<baseuri>_<ver>)中,script 字段是带斜杠的旧格式

/thread/newthread → script: forum/thread/newthread
/user/user         → script: user/login

而 Discuz! X5.0 的 scriptCheck() 要求 script 必须匹配 ^\w+$,也就是纯单段:字符串里不能有斜杠、只能由单词字符组成。分发逻辑为:

$_GET['app'] = $script;
require index.php;   // → source/app/<单段>/<单段>.php

因此,凡是带斜杠的 script 定义,最终都会在 scriptCheck() 处返回 -118 script format is error。这套 Redis 里的接口定义格式属于旧版/错误格式,与 X5.0 的期望不兼容——这是新版发帖打不开的根本原因。

同时确认了另外两条链路的状态:

  • 旧模式(query 参数):发帖可全通,可作为稳定兜底方案。
  • 新版标准模式:卡在 script 格式,需要把接口定义改造成单段格式。

关键机制备忘

  • Redis 键:rApi_<接口> 存接口定义,rApp_<appid> 存应用信息(secret、apis、freq 等)。RESTFUL_REDIS_PREFIX 为空字符串,所以键不带前缀。
  • 脚本执行:根入口按 $_GET['app'] 分发到 source/app/<单段>/<单段>.php(带 \w+ 校验)。
  • 存在单段应用 source/app/forum/forum.php(含 post 模块,具备发帖能力)。
  • 权限校验:apiPermCheck() 读取 token 数据中的 _conf.apis,来自 pre_restful_permission 表的 uri/vN。
  • 应用 appid 格式为「1 + 7 位数字」,secret 由后台生成;Redis rApp_<appid> 读取不到会返回 -110 appid is invalid
  • 注意:若应用建在 UCenter 库上,而 UCenter 的 nginx 未把 /api/restful/ 转发到 PHP 侧,则该入口会 404。

解决方案

新版发帖要打通,推荐按下面顺序尝试:

  1. 修正接口定义为单段 script 格式:在后台重建 RESTful 接口缓存(build_cache_restful())或手动修正 pre_restful_api.data 里的 script 字段为单段(如把 forum/thread/newthread 改成可被分发的单段值)。
  2. 用单段 script + module 参数发帖:直接以 script='forum' 单段 + module 参数尝试调用,验证能否发帖。
  3. 从后台导入官方接口定义:Discuz! 官方在线源 api.witframe.com/discuzrestful 可能存在正确格式的默认接口 XML(如 discuz_restful.xml),可从后台「RESTful 接口 → 导入」引入。
若以上短期都不顺,可直接回退到已全通的旧模式(query 参数)作为稳定方案,先跑通博客→论坛同步,新版标准模式再逐步优化。

总结

正确做法

  • 调用新版 Discuz! X5.0 RESTful API 前,先确认接口定义(Redis rApi_*)里的 script 是单段格式(符合 ^\w+$),否则必然返回 -118
  • 旧模式 API 记得给 URL 补末尾斜杠,避免被重定向。
  • 签名计算要基于 sha256 的 hex digest 再做 base64。
  • 处理这类「官方自带 API」前,先读 source/class/class_restful.php 理清认证、缓存、脚本分发三段逻辑,能大幅缩短定位时间。

参考

  • Typecho 博客:https://blog.example.com
  • Discuz! X5.0 官方源码:https://github.com/DiscuzTeam/DiscuzX

觉得内容不错?我要

评论 暂无评论
暂无评论,快来抢沙发吧~