头像
YIBI

正在加载...

如何为网站配置 GitHub OAuth 登录

2026-06-19GitHubOAuthNuxtDocker部署

概述

本网站使用手写自定义实现(非第三方 auth 模块)支持 GitHub 账号登录。登录后自动使用 GitHub 用户名和头像创建/关联本地用户。配置分为本地测试线上部署两套独立的 OAuth App。


技术架构

  • 服务端路由server/api/auth/github.get.ts(发起授权)、server/api/auth/github/callback.get.ts(处理回调)
  • 认证工具server/utils/auth.ts(JWT 签发/验证、bcrypt 密码哈希)
  • 用户存储.data/db/users.json(JSON 文件数据库,通过 server/utils/db.ts 读写)
  • 环境变量:通过 nuxt.config.tsruntimeConfig 读取,Docker 运行时通过 -e 注入

第一步:创建 GitHub OAuth App

  1. 打开 GitHub Developer Settings
  2. 点击 OAuth AppsNew OAuth App
  3. 填写表单:
字段 本地测试 线上部署
Application name 我的网站-本地 我的网站
Homepage URL http://localhost:3000 https://yibi2333.fun
Authorization callback URL http://localhost:3000/api/auth/github/callback https://yibi2333.fun/api/auth/github/callback
  1. 点击 Register application
  2. 记录 Client ID
  3. 点击 Generate a new client secret,立即复制 Client Secret(只显示一次)
💡 本地和线上各建一个 OAuth App,互不干扰。

第二步:配置环境变量

本地测试

项目根目录 .env 文件(已加入 .gitignore):

bash
# GitHub OAuth(本地)
NUXT_GITHUB_CLIENT_ID=本地ClientID
NUXT_GITHUB_CLIENT_SECRET=本地ClientSecret
NUXT_GITHUB_REDIRECT_URI=http://localhost:3000/api/auth/github/callback
NUXT_PUBLIC_SITE_URL=http://localhost:3000

线上部署

使用 Docker 部署,环境变量通过 -e 参数注入:

bash
docker run -d --name nuxt \
  -v /data/nuxt/.output:/app \
  -w /app \
  -p 3000:3000 \
  --restart unless-stopped \
  -e NUXT_GITHUB_CLIENT_ID=线上ClientID \
  -e NUXT_GITHUB_CLIENT_SECRET=线上ClientSecret \
  -e NUXT_GITHUB_REDIRECT_URI=https://yibi2333.fun/api/auth/github/callback \
  -e NUXT_PUBLIC_SITE_URL=https://yibi2333.fun \
  node:20-alpine node server/index.mjs

环境变量说明

变量 用途 注意
NUXT_GITHUB_CLIENT_ID OAuth App Client ID 服务端可读
NUXT_GITHUB_CLIENT_SECRET OAuth App Client Secret 服务端可读,不可泄露
NUXT_GITHUB_REDIRECT_URI 回调地址 必须与 OAuth App 设置完全一致
NUXT_PUBLIC_SITE_URL 站点地址 public 变量需 NUXT_PUBLIC_ 前缀
⚠️ runtimeConfig.public.* 的环境变量必须用 NUXT_PUBLIC_ 前缀,NUXT_SITE_URL 是错误写法。

第三步:验证

  1. 部署后检查容器环境变量:
  2. bash
    docker exec nuxt env | grep NUXT
  3. 打开网站登录页,点击 GitHub 登录 按钮
  4. 跳转到 GitHub 授权页面 → 确认授权
  5. 自动跳转回网站,完成登录

登录流程

用户点击 GitHub 登录
  → GET /api/auth/github(生成 state 防 CSRF,302 跳转 GitHub)
  → GitHub 授权页(用户确认)
  → 302 回调 /api/auth/github/callback?code=xxx&state=xxx
  → 服务端校验 state,用 code 换取 access_token
  → 获取 GitHub 用户信息(GET api.github.com/user)
  → 查找/创建本地用户记录(users.json)
  → 签发 JWT Token
  → 302 重定向到 /auth/github-callback?token=JWT&username=...
  → 前端页面保存 Token 到 localStorage,跳转首页

安全说明

  • Client Secret 只存在服务端,不暴露给前端
  • OAuth state 参数(UUID v4,5 分钟过期)防 CSRF 攻击
  • 用户密码不存储(GitHub 验证)
  • .env 文件已在 .gitignore 中,不会提交到仓库
  • JWT 密钥从环境变量 NUXT_JWT_SECRET 读取,无环境变量时使用硬编码默认值

常见问题

callback 返回 500 错误

通常是因为 .data/db/ 下的 JSON 文件损坏。检查方法:

bash
# 诊断所有 JSON 文件
docker exec nuxt node -e "
const fs = require('fs');
fs.readdirSync('/app/.data/db').filter(f => f.endsWith('.json')).forEach(f => {
  const p = '/app/.data/db/' + f;
  try { JSON.parse(fs.readFileSync(p,'utf8')); console.log(f + ' OK'); }
  catch(e) { console.log(f + ' BROKEN: ' + e.message); }
});
"

常见 JSON 损坏类型:

  • // 注释行 — JSON 不支持注释
  • 尾部逗号:{ ... }, 后跟 ] — 最后一个元素后不能有逗号

一键修复:

bash
docker exec nuxt node -e "
const fs = require('fs');
const dir = '/app/.data/db';
fs.readdirSync(dir).filter(f => f.endsWith('.json')).forEach(f => {
  const p = dir + '/' + f;
  try { JSON.parse(fs.readFileSync(p,'utf8')); }
  catch(e) {
    let raw = fs.readFileSync(p,'utf8');
    let data = eval('(' + raw + ')');
    fs.writeFileSync(p, JSON.stringify(data, null, 2), 'utf8');
    console.log(f + ' FIXED');
  }
});
"

redirect_uri 不匹配

确保 OAuth App 后台的 Authorization callback URL 与 NUXT_GITHUB_REDIRECT_URI 完全一致

容器重启后登录失败

检查数据库挂载是否持久化(需要挂载 .data/db 目录)


后续优化

  • [x] GitHub 登录
  • [x] 自动同步头像和用户名
  • [ ] 绑定已有账号
  • [ ] 解绑 GitHub 账号