本指南帮助您在5分钟内完成OAuth 2.0服务接入。
打开 https://user.blym.top/admin/oauth_server.php
点击"创建客户端"按钮,填写以下信息:
| 字段 | 说明 | 示例值 |
|---|---|---|
| 客户端名称 | 您的应用名称 | 我的测试应用 |
| 客户端描述 | 应用简介 | 一个示例OAuth客户端 |
| 回调URL | 授权成功后的跳转地址 | https://example.com/callback |
| 允许的作用域 | 请求的权限范围 | openid profile email |
| 机密客户端 | 服务器端应用选"是" | 是 |
| 启用 | 是否启用此客户端 | 是 |
创建成功后,系统显示:
Client ID: client_abc123def456...
Client Secret: xyz789secret000...
⚠️ 重要:Client Secret只显示一次,请立即保存到安全位置!
https://user.blym.top/oauth/authorize.php?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&scope={SCOPES}&state={STATE}
| 参数 | 必填 | 说明 |
|---|---|---|
| client_id | 是 | 客户端ID |
| redirect_uri | 是 | 回调地址,必须与注册时完全一致 |
| response_type | 是 | 固定值 code |
| scope | 否 | 作用域,多个用空格分隔,默认为 openid profile email |
| state | 推荐 | 随机字符串,用于防止CSRF攻击 |
// 生成授权URL
function buildAuthorizationUrl(clientId, redirectUri) {
// 生成随机state
const state = crypto.randomUUID();
// 保存state用于后续验证
sessionStorage.setItem('oauth_state', state);
// 构建URL
const params = new URLSearchParams({
client_id: clientId,
redirect_uri: redirectUri,
response_type: 'code',
scope: 'openid profile email',
state: state
});
return `https://user.blym.top/oauth/authorize.php?${params.toString()}`;
}
// 使用示例
const authUrl = buildAuthorizationUrl(
'client_abc123def456',
'https://example.com/callback'
);
// 跳转到授权页面
window.location.href = authUrl;
<?php
// 生成授权URL
function buildAuthorizationUrl($clientId, $redirectUri) {
// 生成随机state
$state = bin2hex(random_bytes(16));
// 保存state到session
$_SESSION['oauth_state'] = $state;
// 构建URL
$params = http_build_query([
'client_id' => $clientId,
'redirect_uri' => $redirectUri,
'response_type' => 'code',
'scope' => 'openid profile email',
'state' => $state
]);
return 'https://user.blym.top/oauth/authorize.php?' . $params;
}
// 使用示例
$authUrl = buildAuthorizationUrl(
'client_abc123def456',
'https://example.com/callback'
);
// 跳转到授权页面
header('Location: ' . $authUrl);
exit;
?>
用户授权后,系统重定向到您的回调地址:
https://example.com/callback?code=AUTHORIZATION_CODE&state=ORIGINAL_STATE
// 在回调页面验证state
const urlParams = new URLSearchParams(window.location.search);
const returnedState = urlParams.get('state');
const savedState = sessionStorage.getItem('oauth_state');
if (returnedState !== savedState) {
// State不匹配,可能存在CSRF攻击
throw new Error('State验证失败');
}
// 获取授权码
const code = urlParams.get('code');
使用授权码换取访问令牌。
curl -X POST https://user.blym.top/oauth/token.php \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://example.com/callback" \
-d "client_id=client_abc123def456" \
-d "client_secret=xyz789secret000"
async function getAccessToken(code, clientId, clientSecret, redirectUri) {
const response = await fetch('https://user.blym.top/oauth/token.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error_description || error.error);
}
return response.json();
}
// 使用示例
const tokens = await getAccessToken(
code,
'client_abc123def456',
'xyz789secret000',
'https://example.com/callback'
);
console.log('Access Token:', tokens.access_token);
console.log('Refresh Token:', tokens.refresh_token);
console.log('Expires In:', tokens.expires_in);
<?php
function getAccessToken($code, $clientId, $clientSecret, $redirectUri) {
$ch = curl_init('https://user.blym.top/oauth/token.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => $redirectUri,
'client_id' => $clientId,
'client_secret' => $clientSecret
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
$error = json_decode($response, true);
throw new Exception($error['error_description'] ?? $error['error']);
}
return json_decode($response, true);
}
// 使用示例
try {
$tokens = getAccessToken(
$_GET['code'],
'client_abc123def456',
'xyz789secret000',
'https://example.com/callback'
);
// 保存令牌到session
$_SESSION['access_token'] = $tokens['access_token'];
$_SESSION['refresh_token'] = $tokens['refresh_token'];
$_SESSION['token_expires'] = time() + $tokens['expires_in'];
} catch (Exception $e) {
die('获取令牌失败: ' . $e->getMessage());
}
?>
{
"access_token": "at_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_q1r2s3t4u5v6w7x8y9z0a1b2c3d4e5f6",
"scope": "openid profile email"
}
| 字段 | 类型 | 说明 |
|---|---|---|
| access_token | string | 访问令牌,用于调用API |
| token_type | string | 令牌类型,固定为 Bearer |
| expires_in | number | 访问令牌有效期(秒),默认3600秒 |
| refresh_token | string | 刷新令牌,用于获取新的访问令牌 |
| scope | string | 实际授予的作用域 |
使用访问令牌调用用户信息API。
curl -X GET https://user.blym.top/api/userinfo.php \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
async function getUserInfo(accessToken) {
const response = await fetch('https://user.blym.top/api/userinfo.php', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error_description || error.error);
}
return response.json();
}
// 使用示例
const userInfo = await getUserInfo(tokens.access_token);
console.log('用户ID:', userInfo.sub);
console.log('用户名:', userInfo.name);
console.log('邮箱:', userInfo.email);
<?php
function getUserInfo($accessToken) {
$ch = curl_init('https://user.blym.top/api/userinfo.php');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $accessToken
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
$error = json_decode($response, true);
throw new Exception($error['error_description'] ?? $error['error']);
}
return json_decode($response, true);
}
// 使用示例
try {
$userInfo = getUserInfo($_SESSION['access_token']);
echo '用户ID: ' . $userInfo['sub'] . '<br>';
echo '用户名: ' . $userInfo['name'] . '<br>';
echo '邮箱: ' . $userInfo['email'] . '<br>';
} catch (Exception $e) {
// 令牌可能已过期,尝试刷新
echo '获取用户信息失败: ' . $e->getMessage();
}
?>
{
"sub": "123",
"name": "张三",
"preferred_username": "zhangsan",
"email": "zhangsan@example.com",
"email_verified": true,
"client_id": "client_abc123def456",
"scope": "openid profile email"
}
| 字段 | 类型 | 说明 | 所需作用域 |
|---|---|---|---|
| sub | string | 用户唯一标识符 | openid |
| name | string | 用户显示名称 | profile |
| preferred_username | string | 用户名 | profile |
| string | 用户邮箱 | ||
| email_verified | boolean | 邮箱是否已验证 | |
| client_id | string | 客户端ID | - |
| scope | string | 授予的作用域 | - |
┌──────────┐ ┌──────────────────┐
│ │ 1. 点击"使用user.blym.top登录" │ │
│ 用户 │ ────────────────────────────────────>│ 您的应用 │
│ │ │ │
└────┬─────┘ └────────┬─────────┘
│ │
│ 2. 重定向到授权页面 │
│ <───────────────────────────────────────────────────┤
│ https://user.blym.top/oauth/authorize.php? │
│ client_id=xxx&redirect_uri=xxx&... │
│ │
│ 3. 用户登录并授权 │
│ ────────────────────────────────────>┌──────────────┴──────────┐
│ │ user.blym.top │
│ 4. 重定向回回调地址,附带授权码 │ OAuth授权服务器 │
│ <────────────────────────────────────┤ │
│ https://example.com/callback? └──────────────┬──────────┘
│ code=AUTH_CODE&state=xxx │
│ │
│ 5. 用授权码换取令牌
│ ─────────────────────>│
│ │
│ 6. 返回访问令牌
│ <─────────────────────┤
│ │
│ 7. 获取用户信息
│ ─────────────────────>│
│ │
│ 8. 返回用户信息
│ <─────────────────────┤
│ │
│ 9. 登录成功,显示用户信息 │
│ <───────────────────────────────────────────────────┤
│ │
▼ ▼