构造网页授权链接
本文档介绍如何构造 OAuth 2.0 授权链接,引导用户进行授权。
授权链接格式
https://platform.com/connect/oauth2/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&scope={SCOPE}&state={STATE}
参数说明
| 参数 | 必须 | 说明 |
|---|---|---|
| client_id | 是 | 客户端 ID,在平台创建客户端时获取 |
| redirect_uri | 是 | 授权回调地址,必须与创建客户端时配置的地址一致 |
| response_type | 是 | 固定值:code |
| scope | 否 | 授权范围,当前支持:basic |
| state | 否 | 自定义状态值,用于防止 CSRF 攻击。建议使用随机字符串 |
参数详解
client_id(必须)
客户端 ID,是 OAuth 客户端的唯一标识符。
- 在平台 开发管理 > 开发设置 > OAuth 客户端 中创建
- 为 32 位 GUID 格式,如:
1c1e3458cd4344fbbeea2a8103d6ab44 - 每个客户端有唯一的 Client ID
redirect_uri(必须)
授权回调地址,用户授权后跳转的目标地址。
- 必须在创建客户端时配置
- 支持配置多个回调地址
- 生产环境必须使用 HTTPS
- 回调地址必须完全匹配,包括协议、域名、端口、路径
注意事项:
- URL 需要进行编码(URL Encode)
- 必须与创建客户端时配置的地址完全一致
- 区分大小写
response_type(必须)
响应类型,固定为 code,表示使用授权码模式。
scope(可选)
授权范围,用于限制访问令牌的权限。
- 当前仅支持:
basic - 多个范围使用空格分隔(未来可能支持)
state(推荐)
自定义状态值,用于防止 CSRF 攻击。
- 建议使用随机字符串或 GUID
- 在回调时会原样返回
- 用于验证请求的合法性
安全建议:
- 使用足够长度的随机字符串
- 每次请求使用不同的 state 值
- 在回调时验证 state 是否一致
请求示例
完整示例
https://platform.com/connect/oauth2/authorize?client_id=1c1e3458cd4344fbbeea2a8103d6ab44&redirect_uri=https://your-app.com/callback&response_type=code&scope=basic&state=ad5c782f-33ee-4e30-ad9b-01d30f02a796
URL 编码示例
https://platform.com/connect/oauth2/authorize?client_id=1c1e3458cd4344fbbeea2a8103d6ab44&redirect_uri=https%3A%2F%2Fyour-app.com%2Fcallback&response_type=code&scope=basic&state=ad5c782f-33ee-4e30-ad9b-01d30f02a796
代码示例
JavaScript
// 配置
const CLIENT_ID = 'your_client_id';
const REDIRECT_URI = 'https://your-app.com/callback';
const PLATFORM_URL = 'https://platform.com';
// 生成随机 state
function generateState() {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
// 构造授权链接
function buildAuthUrl() {
const state = generateState();
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
response_type: 'code',
scope: 'basic',
state: state
});
const authUrl = `${PLATFORM_URL}/connect/oauth2/authorize?${params}`;
// 保存 state 用于后续验证
sessionStorage.setItem('oauth_state', state);
return authUrl;
}
// 跳转到授权页面
window.location.href = buildAuthUrl();
Python
from urllib.parse import urlencode
import secrets
# 配置
CLIENT_ID = 'your_client_id'
REDIRECT_URI = 'https://your-app.com/callback'
PLATFORM_URL = 'https://platform.com'
# 生成随机 state
def generate_state():
return secrets.token_urlsafe(16)
# 构造授权链接
def build_auth_url():
state = generate_state()
params = {
'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI,
'response_type': 'code',
'scope': 'basic',
'state': state
}
auth_url = f"{PLATFORM_URL}/connect/oauth2/authorize?{urlencode(params)}"
# 保存 state 用于后续验证
# 在实际应用中,应该存储在 session 或数据库中
print(f"State: {state}")
return auth_url
print(f"授权链接: {build_auth_url()}")
授权流程
用户访问授权链接后,会经历以下步骤:
-
检查登录状态
- 如果用户未登录,跳转到登录页面
- 如果用户已登录,直接进入授权流程
-
用户授权
- 当前为静默授权模式,自动完成授权
- 未来可能支持用户手动授权
-
重定向回调
- 授权成功后,重定向到
redirect_uri - 携带
code和state参数
- 授权成功后,重定向到
回调处理
授权成功后,平台会重定向到回调地址:
https://your-app.com/callback?code={CODE}&state={STATE}
回调参数
| 参数 | 说明 |
|---|---|
| code | 授权码,用于换取访问令牌 |
| state | 原样返回的 state 值,用于验证请求的合法性 |
验证 state
// 获取回调参数
const urlParams = new URLSearchParams(window.location.search);
const receivedState = urlParams.get('state');
const expectedState = sessionStorage.getItem('oauth_state');
// 验证 state
if (receivedState !== expectedState) {
throw new Error('State 验证失败,可能存在 CSRF 攻击');
}
// 获取 code
const code = urlParams.get('code');
console.log('授权码:', code);
常见问题
Q1: 提示 "redirect_uri_mismatch"?
原因:回调地址与配置的不一致。
解决:
- 检查 redirect_uri 参数是否与创建客户端时配置的完全一致
- 注意 URL 编码问题
- 确保协议、域名、端口、路径都一致
Q2: 授权页面一直加载?
原因:可能是参数错误或网络问题。
解决:
- 检查 client_id 是否正确
- 检查网络连接是否正常
- 检查租户 ID 是否正确
Q3: 如何处理 URL 编码?
建议:
- 使用 URLSearchParams 或 urlencode 函数自动编码
- 不要手动编码,容易出错
- 注意特殊字符的处理
安全建议
-
使用 state 参数
- 每次请求生成不同的随机 state
- 在回调时验证 state 的合法性
-
使用 HTTPS
- 生产环境必须使用 HTTPS
- 防止参数被劫持
-
保护 Client Secret
- 不要在客户端代码中暴露 Client Secret
- 使用环境变量存储敏感信息