GitHub

鲲 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.tsruntimeConfig 中配置:

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 账号登录」按钮,点击后:

  1. 调用 generateCodeVerifier()generateCodeChallenge()generateState()
  2. code_verifierstate 存入 sessionStorage
  3. 构建授权 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

  1. 从 URL query 读取 codestate
  2. sessionStorage 读取之前保存的 statecode_verifier
  3. 验证 state 一致性
  4. 调用自己的服务端 API /api/auth/oauth-callback,传入 codecode_verifier
  5. 成功后跳转首页,失败时跳转登录页显示错误

5. 服务端回调处理

创建 server/api/auth/oauth-callback.post.ts

  1. 接收客户端传来的 codecode_verifier
  2. 调用 OAuth Server 的 /oauth/token
{
  "grant_type": "authorization_code",
  "code": "<授权码>",
  "redirect_uri": "<回调地址>",
  "client_id": "<客户端ID>",
  "client_secret": "<客户端密钥>",
  "code_verifier": "<PKCE验证器>"
}
  1. 用返回的 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
  }
}
  1. sub(用户UUID)在本站数据库查找或创建用户
  2. 创建本站 session
  3. 将 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 令牌已过期 重新登录

安全要求

  1. client_secret 只能在服务端使用(server/ 目录下),绝不暴露到客户端
  2. 始终验证 state 参数防止 CSRF
  3. refresh_token 存储在 httpOnly cookie 或服务端 session 中
  4. 使用 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