同一个 REST 请求在测试环境返回 401,换一个 Token 后变成 403。两者都叫“没权限”,但定位层级不同:401 通常说明认证凭据缺失、过期或无法验证;403 通常说明系统已经知道你是谁,却不允许访问目标 ACL 资源。
401 先查请求有没有正确携带身份
确认 Authorization: Bearer ... 没被反向代理剥离,Token 没有多余空格,调用域名与环境匹配。管理员 Token、客户 Token 和 Integration OAuth 的适用端点不同,不能互换。
curl -i -H 'Authorization: Bearer REDACTED' 'https://www.example.com/rest/V1/store/storeConfigs'
不要在终端历史、工单或文章中保存真实 Token。日志只记录哈希片段和请求 ID。
403 查 Web API resource ACL
打开目标模块的 webapi.xml,查看 route 对应 resource。Integration 在后台选择的资源必须包含它;修改权限后重新授权/激活流程是否需要生成新 Token,取决于集成类型。自定义接口若把 resource 写错或引用不存在 ACL,也会一直 403。
客户身份还有业务级授权
客户 Token 只能访问自己的购物车、订单和地址。尝试读取另一个 customer_id,即使 ACL 名称相同,也应被拒绝。不要为了让移动端工作把接口 resource 改成 anonymous,这会把数据暴露给所有人。
WAF 与代理可能伪装状态码
响应体不是 Magento JSON、响应头带边缘 request ID,说明 401/403 可能来自 CDN、Basic Auth 或 WAF。比较应用日志是否出现同一请求,确认请求有没有到 Magento。浏览器 CORS preflight 的 403 也与 API Token 权限不同。
建立最小权限测试
用同一身份先调用一个确定允许的端点,再调用目标端点;用只读与写入请求分别测试。修复后撤销临时全权限,重新用最小 Integration 资源验证。最终不仅要返回 200,还要证明 Token 无法访问未授权资源。
接口版本与 Store Code 也会改变结果
/rest/default/V1/... 与其他 store code 可能进入不同网站范围,自定义授权插件会据此限制资源。确认调用方没有把环境 Base URL、store code 或 API 前缀写死。端点不存在通常应是 404,但某些安全层会统一返回 403,因此仍需结合 Magento 路由日志判断。
自动化测试应覆盖 Token 过期、被撤销、权限减少和跨客户访问,防止升级后把原本的 403 变成数据泄露。
调用方对 401 可以触发一次受控的重新认证,对 403 则不应无限刷新 Token;权限不足不会因换一个同身份 Token 自动消失。把两种状态都当成“重新登录”会形成请求风暴,也会掩盖 Integration ACL 的真实缺口。

