鲲 Galgame OAuth 接入 — Nuxt 项目实施提示词
本文档是给 AI 编码助手(如 Claude)的提示词,用于在 Nuxt 3/4 项目中实现 鲲 Galgame OAuth 登录功能。 将本文件内容作为 context 提供给 AI,它就能正确编写对接代码。
任务
在当前 Nuxt 项目中接入 鲲 Galgame OAuth 2.0 登录系统,实现「使用 KUN 账号登录」功能。
OAuth Server 信息
- 生产环境 Base URL:
https://oauth.kungal.com/api/v1 - 开发环境 Base URL:
http://127.0.0.1:9277/api/v1 - 协议: OAuth 2.0 Authorization Code + PKCE (S256)
端点
| 端点 | 方法 | 说明 |
|---|---|---|
/oauth/authorize |
GET | 获取授权码(用户必须已登录 OAuth Server) |
/oauth/token |
POST | 用授权码换取 token |
/oauth/userinfo |
GET | 用 access_token 获取用户信息 |
/oauth/revoke |
POST | 吊销 refresh_token |
需要实现的文件
1. 环境变量
# .env
NUXT_OAUTH_SERVER_URL=https://oauth.kungal.com/api/v1
NUXT_PUBLIC_OAUTH_CLIENT_ID=<从管理后台获取>
NUXT_OAUTH_CLIENT_SECRET=<从管理后台获取>
NUXT_PUBLIC_OAUTH_REDIRECT_URI=https://www.kungal.com/auth/callback
在 nuxt.config.ts 的 runtimeConfig 中配置:
runtimeConfig: {
oauthServerUrl: process.env.NUXT_OAUTH_SERVER_URL,
oauthClientSecret: process.env.NUXT_OAUTH_CLIENT_SECRET,
public: {
oauthClientId: process.env.NUXT_PUBLIC_OAUTH_CLIENT_ID,
oauthRedirectUri: process.env.NUXT_PUBLIC_OAUTH_REDIRECT_URI,
},
},
2. PKCE 工具函数(客户端)
创建 utils/oauth-pkce.ts,包含:
generateCodeVerifier()— 生成 43-128 字符随机字符串(base64url 编码)generateCodeChallenge(verifier)— SHA256(verifier) 的 base64url 编码generateState()— 16 字节随机 hex 字符串
使用 crypto.getRandomValues() 和 crypto.subtle.digest('SHA-256', ...) 实现。
3. 登录触发(客户端)
在登录页面添加一个「使用 KUN 账号登录」按钮,点击后:
- 调用
generateCodeVerifier()和generateCodeChallenge()和generateState() - 将
code_verifier和state存入sessionStorage - 构建授权 URL 并跳转:
{oauthServerUrl}/oauth/authorize?
client_id={clientId}&
redirect_uri={redirectUri}&
response_type=code&
scope=openid+profile&
state={state}&
code_challenge={codeChallenge}&
code_challenge_method=S256
4. 回调页面(客户端)
创建 pages/auth/callback.vue:
- 从 URL query 读取
code和state - 从
sessionStorage读取之前保存的state和code_verifier - 验证
state一致性 - 调用自己的服务端 API
/api/auth/oauth-callback,传入code和code_verifier - 成功后跳转首页,失败时跳转登录页显示错误
5. 服务端回调处理
创建 server/api/auth/oauth-callback.post.ts:
- 接收客户端传来的
code和code_verifier - 调用 OAuth Server 的
/oauth/token:
{
"grant_type": "authorization_code",
"code": "<授权码>",
"redirect_uri": "<回调地址>",
"client_id": "<客户端ID>",
"client_secret": "<客户端密钥>",
"code_verifier": "<PKCE验证器>"
}
- 用返回的
data.access_token调用/oauth/userinfo获取用户信息:
// GET /oauth/userinfo, Authorization: Bearer <access_token>
// 响应:
{
"code": 0,
"message": "成功",
"data": {
"sub": "用户UUID(唯一标识)",
"name": "用户名",
"email": "邮箱",
"picture": "头像URL",
"updated_at": 1234567890
}
}
- 用
sub(用户UUID)在本站数据库查找或创建用户 - 创建本站 session
- 将 OAuth 的
refresh_token安全存储(用于后续刷新)
6. Token 刷新
当 access_token 过期(15 分钟)时,调用:
POST /oauth/token
{
"grant_type": "refresh_token",
"refresh_token": "<之前保存的>",
"client_id": "<客户端ID>",
"client_secret": "<客户端密钥>"
}
重要:每次刷新会返回新的 refresh_token(令牌轮换),必须更新保存的值。
7. 登出
用户在本站登出时,同时吊销 OAuth 令牌:
POST /oauth/revoke
{ "token": "<refresh_token>" }
API 响应格式
所有 OAuth Server 的 API 响应使用统一格式:
{
"code": 0, // 0=成功, 非零=错误码
"message": "成功",
"data": { ... }
}
包括 /oauth/token 和 /oauth/userinfo,实际数据都在 data 字段中。
错误处理
| 错误码 | 含义 | 处理 |
|---|---|---|
| 15001 | 无效的客户端 | 检查 client_id |
| 15002 | 无效的回调地址 | 检查 redirect_uri 是否已注册 |
| 15003 | 无效的授权码 | 重新走授权流程 |
| 15004 | PKCE 验证失败 | 检查 code_verifier 生成逻辑 |
| 10003 | 令牌已过期 | 重新登录 |
安全要求
client_secret只能在服务端使用(server/目录下),绝不暴露到客户端- 始终验证
state参数防止 CSRF refresh_token存储在 httpOnly cookie 或服务端 session 中- 使用 PKCE (S256) 即使有 client_secret
数据库
本站需要一张表关联 OAuth 用户和本站用户:
CREATE TABLE oauth_accounts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
provider VARCHAR(50) NOT NULL DEFAULT 'kun-oauth',
provider_account_id VARCHAR(255) NOT NULL, -- 存 userinfo 返回的 sub (UUID)
access_token TEXT,
refresh_token TEXT,
expires_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(provider, provider_account_id)
);
用 provider_account_id(即 userinfo 的 sub 字段)作为用户在 OAuth 系统中的唯一标识。
源:kun-galgame-infra/docs/integration/oauth/nuxt-integration-prompt.md