获取访问令牌
本文档介绍如何使用授权码换取访问令牌(Access Token)。
API 接口
POST /api/OAuth2/Token
请求参数
Header 参数
| 参数 | 必须 | 类型 | 说明 |
|---|---|---|---|
| Content-Type | 是 | string | 固定值:application/json |
| X-Tenant-Id | 是 | string | 租户 ID |
Body 参数
| 参数 | 必须 | 类型 | 说明 |
|---|---|---|---|
| client_id | 是 | string | 客户端 ID |
| secret | 是 | string | 客户端密钥 |
| code | 是 | string | 授权码 |
请求示例
HTTP 请求
POST /api/OAuth2/Token HTTP/1.1
Host: your-platform.com
Content-Type: application/json
X-Tenant-Id: develop
{
"client_id": "1c1e3458cd4344fbbeea2a8103d6ab44",
"secret": "Pr#2_-vVNCN8joLOJ#kXyzZ2*UBJh!2V",
"code": "4bed401590f94bd1a76c0a2e1d5b5788"
}
cURL 请求
curl -X POST "https://platform.com/api/OAuth2/Token" \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: your_tenant_id" \
-d '{
"client_id": "your_client_id",
"secret": "your_client_secret",
"code": "your_code"
}'
响应格式
成功响应
{
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 7200
},
"total": 0,
"action": 0,
"code": 200,
"message": "操作成功",
"moreMessage": null
}
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| access_token | string | 访问令牌,用于调用平台接口 |
| token_type | string | 令牌类型,固定为 Bearer |
| expires_in | number | 令牌有效期(秒) |
错误响应
{
"data": null,
"total": 0,
"action": 1,
"code": 510,
"message": "操作失败",
"moreMessage": "授权码无效或已过期"
}
代码示例
JavaScript
// 配置
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
const PLATFORM_URL = 'https://platform.com';
const TENANT_ID = 'your_tenant_id';
// 使用授权码换取访问令牌
async function getAccessToken(code) {
const response = await fetch(
`${PLATFORM_URL}/api/OAuth2/Token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Tenant-Id': TENANT_ID
},
body: JSON.stringify({
client_id: CLIENT_ID,
secret: CLIENT_SECRET,
code: code
})
}
);
const result = await response.json();
if (result.code === 200 && result.data) {
return result.data;
} else {
throw new Error(result.moreMessage || '获取访问令牌失败');
}
}
// 使用示例
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
getAccessToken(code)
.then(tokenData => {
console.log('访问令牌:', tokenData.access_token);
console.log('令牌类型:', tokenData.token_type);
console.log('有效期:', tokenData.expires_in, '秒');
})
.catch(error => {
console.error('错误:', error.message);
});
Python
import requests
# 配置
CLIENT_ID = 'your_client_id'
CLIENT_SECRET = 'your_client_secret'
PLATFORM_URL = 'https://platform.com'
TENANT_ID = 'your_tenant_id'
# 使用授权码换取访问令牌
def get_access_token(code):
url = f"{PLATFORM_URL}/api/OAuth2/Token"
headers = {
'Content-Type': 'application/json',
'X-Tenant-Id': TENANT_ID
}
data = {
'client_id': CLIENT_ID,
'secret': CLIENT_SECRET,
'code': code
}
response = requests.post(url, json=data, headers=headers)
result = response.json()
if result.get('code') == 200 and result.get('data'):
return result['data']
else:
raise Exception(result.get('moreMessage', '获取访问令牌失败'))
# 使用示例
code = 'your_authorization_code'
try:
token_data = get_access_token(code)
print(f"访问令牌: {token_data['access_token']}")
print(f"令牌类型: {token_data['token_type']}")
print(f"有效期: {token_data['expires_in']} 秒")
except Exception as e:
print(f"错误: {str(e)}")
令牌管理
存储令牌
访问令牌需要妥善存储,避免泄露:
// 存储到会话存储(推荐)
sessionStorage.setItem('access_token', tokenData.access_token);
sessionStorage.setItem('token_expires_at', Date.now() + tokenData.expires_in * 1000);
// 或者存储到内存中
let accessToken = {
token: tokenData.access_token,
expiresAt: Date.now() + tokenData.expires_in * 1000
};
检查令牌有效性
// 检查令牌是否过期
function isTokenExpired() {
const expiresAt = parseInt(sessionStorage.getItem('token_expires_at'));
return Date.now() >= expiresAt;
}
// 获取有效的访问令牌
function getValidToken() {
if (isTokenExpired()) {
// 令牌已过期,需要重新授权
sessionStorage.removeItem('access_token');
sessionStorage.removeItem('token_expires_at');
return null;
}
return sessionStorage.getItem('access_token');
}
使用令牌调用接口
// 使用访问令牌调用 API
async function callApi(url, options = {}) {
const token = getValidToken();
if (!token) {
throw new Error('访问令牌无效或已过期');
}
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
...options.headers
};
const response = await fetch(url, {
...options,
headers
});
return response.json();
}
错误处理
常见错误
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| 授权码无效或已过期 | code 已使用或超时 | 重新获取授权码 |
| 客户端 ID 无效 | client_id 错误 | 检查 client_id 是否正确 |
| 客户端密钥错误 | secret 错误 | 检查 secret 是否正确 |
| 租户 ID 无效 | X-Tenant-Id 错误 | 检查租户 ID 是否正确 |
错误处理示例
async function getAccessToken(code) {
try {
const response = await fetch(
`${PLATFORM_URL}/api/OAuth2/Token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Tenant-Id': TENANT_ID
},
body: JSON.stringify({
client_id: CLIENT_ID,
secret: CLIENT_SECRET,
code: code
})
}
);
const result = await response.json();
if (result.code === 200 && result.data) {
return result.data;
} else {
// 处理业务错误
const errorMsg = result.moreMessage || result.message || '未知错误';
throw new Error(errorMsg);
}
} catch (error) {
// 处理网络错误或其他异常
console.error('获取访问令牌失败:', error);
throw error;
}
}
注意事项
-
授权码有效期
- 授权码(code)有效期很短,通常只有几分钟
- 获取到 code 后应立即换取 token
- 每个 code 只能使用一次
-
访问令牌有效期
- 访问令牌有效期通常为 2 小时(7200 秒)
- 在令牌即将过期时需要重新授权
- 建议在令牌过期前 5 分钟重新获取
-
安全建议
- 不要在客户端代码中暴露 Client Secret
- 使用 HTTPS 传输数据
- 妥善存储访问令牌
常见问题
Q1: Token 获取失败?
原因:可能是 code 过期或参数错误。
解决:
- 检查 code 是否正确且未过期
- 检查 client_id 和 secret 是否正确
- 检查租户 ID 是否正确
Q2: 如何判断令牌是否过期?
方法:
- 记录令牌的过期时间(expires_at = 当前时间 + expires_in)
- 每次使用前检查当前时间是否超过过期时间
- 建议提前 5 分钟刷新令牌
Q3: 令牌过期后如何处理?
处理方式:
- 清除本地存储的令牌
- 重新引导用户授权
- 获取新的授权码和访问令牌