第三方 OAuth 接入权限与安全
回调地址策略
五种回调平台、地址形状规则、匹配语义与端口放宽的边界。
回调地址是授权码的投递地址,也是整个流程里最容易被配错的一环。本页把「什么地址能登记」「什么地址能命中」讲清楚。
五种平台
| 平台 | 地址形状 | 是否需密钥 | 访问令牌 | 刷新令牌 |
|---|---|---|---|---|
web_server | https://host/path,本机回环可用 http://localhost/path | ✅ 机密 | 1 小时 | 30 天 |
web_client | 同上 | ❌ 公开 | 30 分钟 | 14 天 |
desktop | 回环地址(带路径)或自定义 scheme,如 myapp://callback | ❌ 公开 | 30 分钟 | 14 天 |
ios_macos | 仅 com.muoceon.<bundle-id>://auth | ❌ 公开 | 30 分钟 | 14 天 |
android | 仅 com.muoceon.<package>://auth/<43 位签名哈希> | ❌ 公开 | 30 分钟 | 14 天 |
令牌有效期取决于客户端是否持有密钥,而不是平台本身:机密客户端有服务端兜底,令牌可以长一些;公开客户端的令牌落在用户设备上,泄漏后没有第二道防线,只能靠短有效期。
通用校验(所有平台)
登记与匹配时都会重新做一遍:
- 长度不超过 2048 字符,不含空白字符。
- 必须能解析成合法 URL。
- 不允许 query、fragment、用户名或密码:
https://example.com/cb?x=1❌https://example.com/cb#frag❌https://user:pass@example.com/cb❌
- scheme 黑名单:
javascript、data、file、blob、about、vbscript。这些 scheme 会「执行内容」而不是「把用户送回来」,放行等于把授权码交给一段脚本。
各平台的形状规则
web_server / web_client
- 必须是
https,且必须带非根路径:https://example.com/cb✅,https://example.com❌。 - 本机回环允许
http:http://localhost:3000/callback✅。
desktop
两种形态二选一:
- 回环地址且带路径:
http://127.0.0.1:51789/callback✅。 - 自定义 scheme(非
http/https):myapp://callback✅。
ios_macos / android
只接受按约定生成的反向域名 scheme,不允许自由填写:
com.muoceon.com.yourcompany.yourapp://auth
com.muoceon.com.yourcompany.yourapp://auth/<签名哈希>Android 末段是 43 个字符的签名哈希(A-Z、a-z、0-9、-、_)。iOS 与 Android 各自使用独立 scheme,避免多个应用声明同一 scheme 后由系统弹选择器分流。
匹配语义
授权请求里的 redirect_uri 与可用登记行做比较:
- 全等优先:规范化后整串相等才算命中(协议、主机、端口、路径、末尾斜杠都在内)。
- 回环端口放宽:登记地址与请求地址都是回环主机(
localhost/127.0.0.1/[::1])时,只忽略端口,路径仍须一致。这条只对web_server、web_client、desktop生效。 - 未携带
redirect_uri:只有当该客户端恰好一条可用登记行时才回退到它;存在多条登记行时直接拒绝——多条意味着平台无法推断,回退到任意一条等于把授权码投到猜测出来的地址。
请求必须带 redirect_uri
回退逻辑只是兜底。生产环境请在授权请求与换令牌请求里都显式携带同一个 redirect_uri,
否则一旦以后给客户端加了第二条回调地址,原本能跑通的流程会突然失败。
平台与密钥必须一致
只有 web_server 预设「客户端持有密钥」,其余四个平台都跑在用户设备上。因此:
web_server的回调行不能挂在没有密钥的客户端上(行在自称「我有服务端」,客户端却拿不出密钥)。- 设备端形态的回调行不能挂在有机密的客户端上(机密客户端处处要出示密钥,把它放进分发包或浏览器等于公开密钥)。
同一个客户端的全部可用回调行必须属于同一档。需要同时具备服务端与设备端形态时,拆成两个客户端。
常见拒绝原因
| 现象 | 原因 |
|---|---|
| 授权请求被拒,提示回调地址非法 | 地址未登记;或与登记值差一个末尾斜杠 / 端口(非回环)/ 大小写主机名 |
换令牌 invalid_grant | 换令牌时带的 redirect_uri 与授权请求时不一致 |
| 本地能跑、线上不行 | 本地用回环 http 侥幸命中,生产地址不是 https 或缺少路径 |
| 移动端回调打不开应用 | scheme 不符合 com.muoceon.<bundle-id>://auth 约定 |