对接第三方开放平台(如登录授权、内容服务、支付服务等)时,OAuth 2.0 授权流程是必经之路。不同平台的实现细节略有差异,但核心流程一致。本文总结对接过程中的关键步骤与常见坑。
一、OAuth 2.0 授权码模式流程
目前绝大多数开放平台采用授权码模式(Authorization Code),完整流程如下:
- 客户端拼接授权 URL,携带
app_id、redirect_uri、state参数,引导用户跳转到授权页 - 用户在授权页确认授权,平台跳转回
redirect_uri并携带code和state - 服务端用
code换取access_token和refresh_token - 服务端携带
access_token调用业务 API - token 过期后用
refresh_token刷新,避免用户重新授权
二、授权 URL 与 redirect_uri
// 构造授权 URL 示例
const authUrl = 'https://open.example.com/oauth/authorize'
+ '?app_id=' + encodeURIComponent(APP_ID)
+ '&redirect_uri=' + encodeURIComponent(REDIRECT_URI)
+ '&response_type=code'
+ '&scope=' + encodeURIComponent('user_info')
+ '&state=' + state; // 防 CSRF 随机串
有几个关键点:
- redirect_uri 必须白名单化:在开放平台后台配置的域名必须与请求中的回调地址完全一致,包括协议和路径
- state 参数必带:用于防止 CSRF,回调时校验 state 是否与发起时一致
- scope 按需申请:只申请用到的权限,避免不必要的审核门槛
三、code 换 token 的坑
// 服务端用 code 换 token
const tokenRes = await fetch('https://open.example.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
app_id: APP_ID,
app_secret: APP_SECRET,
code: code,
}),
});
常见的坑:
- code 一次性有效:兑换失败后不能重试同一个 code,需让用户重新授权
- code 有效期极短:通常几分钟,收到后要立即兑换
- 换 token 要在服务端做:app_secret 绝不能暴露在前端
- 注意 token URL 的 Content-Type:很多平台要求
application/x-www-form-urlencoded而不是 JSON
四、token 管理与刷新
// 刷新 access_token
async function refreshAccessToken(refreshToken) {
const res = await fetch('https://open.example.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
app_id: APP_ID,
app_secret: APP_SECRET,
refresh_token: refreshToken,
}),
});
return res.json();
}
建议:
- token 加密存储,或至少做好权限隔离
- 维护
expires_in,在过期前提前刷新,避免调用失败 - 刷新逻辑加并发控制,防止多个请求同时刷新导致 token 失效
五、回调与验签
部分平台(如支付、消息通知类)会主动向你的服务器推送回调。务必做好验签,防止伪造请求:
// 验签逻辑示意
function verifySignature(params, signature, secret) {
const sorted = Object.keys(params).sort();
const raw = sorted.map(k => k + '=' + params[k]).join('&');
const expected = crypto.createHmac('sha256', secret).update(raw).digest('hex');
return expected === signature;
}
回调处理要求:
- 收到回调先验签,再处理业务,最后返回成功应答
- 回调可能重复推送,业务处理要保证幂等
- 回调接口响应要及时(平台通常有超时重试机制)
六、错误码排查思路
对接中最消耗时间的是联调阶段,常见错误码分几类:
- 参数错误(4xx):检查参数名、编码、必填项,尤其是 access_token 是否传在正确的位置(header 还是 query)
- 权限错误:scope 未申请、应用未上线、接口白名单未配置
- 频率限制:超出调用 QPS,需要退避重试或升级配额
- token 失效:先刷新再重试一次,仍失败则重新授权
小结
开放平台对接的本质是"规范地处理状态与错误"。把授权、验签、token 管理这几个环节做扎实,大部分联调问题都能迎刃而解。建议在代码中埋好关键节点的日志,遇到问题能快速定位。