@idevless/nuxt-auth
v1.0.4
Published
Nuxt OAuth
Maintainers
Readme
Nuxt OAuth
一个简单易用的 Nuxt OAuth 认证模块,支持多种主流 OAuth 提供商。
✨ 特性
- 🛡️ 内置 CSRF 保护(基于 cookie 的状态验证)
- 📦 TypeScript 支持
- 🎯 简单的配置和使用
📦 安装
# 使用 Nuxi 添加模块(推荐)
npx nuxi module add @idevless/nuxt-oauth
# 或者手动安装
npm install @idevless/nuxt-oauth
# yarn add @idevless/nuxt-oauth
# pnpm add @idevless/nuxt-oauth🚀 快速开始
1. 添加模块到 Nuxt 配置
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@idevless/nuxt-oauth'],
runtimeConfig: {
oauth: {
enableState: true, // 启用 CSRF 保护
defaultCallbackPath: '/', // 认证成功后的默认跳转路径
providers: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
scopes: ['user:email'] // 可选,默认为空数组
},
feishu: {
clientId: process.env.FEISHU_CLIENT_ID,
clientSecret: process.env.FEISHU_CLIENT_SECRET,
scopes: [] // 可选
}
}
}
}
})2. 创建 OAuth 路由处理器
授权入口路由
创建 server/routes/oauth/[provider].get.ts:
export default defineGatewayEventHandler({
// 可选:重定向前的回调
onBeforeRedirect: (event, { providerName, state }) => {
console.log(`准备跳转到 ${providerName} 进行授权`)
},
// 可选:错误处理
onError: (event, error) => {
console.error('OAuth 授权错误:', error)
}
})回调路由
创建 server/routes/oauth/callback/[provider].get.ts:
export default defineCallbackEventHandler({
// 认证成功回调
onSuccess: (event, { providerName, tokenData, userInfo, state }) => {
console.log('认证成功:', {
provider: providerName,
user: userInfo,
token: tokenData
})
// 在这里可以:
// 1. 将用户信息保存到数据库
// 2. 创建会话
// 3. 设置 JWT token
// 4. 其他业务逻辑
},
// 可选:错误处理
onError: (event, error) => {
console.error('OAuth 回调错误:', error)
// 重定向到错误页面
return sendRedirect(event, '/?error=' + encodeURIComponent(error.message))
}
})3. 在前端创建登录链接
<template>
<div>
<h1>登录</h1>
<a href="/oauth/github" class="btn">使用 GitHub 登录</a>
<a href="/oauth/feishu" class="btn">使用飞书登录</a>
</div>
</template>🔧 配置选项
运行时配置
interface RuntimeConfig {
oauth: {
enableState?: boolean // 是否启用 CSRF 保护,默认 false
defaultCallbackPath?: string // 认证成功后的默认跳转路径,默认 '/'
providers: {
[providerName: string]: {
clientId: string
clientSecret: string
scopes?: string[] // OAuth 作用域,默认为空数组
}
}
}
}环境变量
推荐使用环境变量来配置敏感信息:
# .env
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
FEISHU_CLIENT_ID=your_feishu_client_id
FEISHU_CLIENT_SECRET=your_feishu_client_secret📚 支持的提供商
GitHub
// 用户信息类型
interface GitHubUser {
id: number
name: string | null
avatar_url: string
email: string | null
login: string
url: string
}
// Token 信息类型
interface GitHubToken {
access_token: string
token_type: string
scope: string
}配置 GitHub OAuth 应用:
- 访问 GitHub Developer Settings
- 创建新的 OAuth 应用
- 设置回调 URL:
http://localhost:3000/oauth/callback/github
飞书 (Feishu)
// 用户信息类型
interface FeishuUser {
user_id: string
open_id: string
union_id: string
name?: string
en_name?: string
avatar_url: string
email?: string
mobile?: string
tenent_key?: string
enterprise_email?: string
employee_no?: string
}
// Token 信息类型
interface FeishuToken {
access_token: string
expires_in: number
refresh_token?: string
refresh_token_expires_in?: number
scope: string
}配置飞书 OAuth 应用:
- 访问 飞书开放平台
- 创建企业自建应用
- 配置重定向 URL:
http://localhost:3000/oauth/callback/feishu
🔒 安全性
CSRF 保护
启用 enableState: true 来开启 CSRF 保护:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
oauth: {
enableState: true // 启用状态验证
// ...
}
}
})当启用状态验证时,模块会:
- 在授权请求中生成随机 state 参数
- 将 state 存储在 HTTP-only cookie 中
- 在回调中验证 state 参数是否匹配
Cookie 安全
State cookie 的安全配置:
httpOnly: 在 HTTPS 环境下自动启用secure: 在 HTTPS 环境下自动启用sameSite: 设置为 'lax'maxAge: 10 分钟过期
🛠️ 高级用法
自定义错误处理
export default defineCallbackEventHandler({
onError: async (event, error) => {
// 记录错误日志
console.error('OAuth 认证失败:', error)
// 重定向到自定义错误页面
return sendRedirect(event, `/auth/error?message=${encodeURIComponent(error.message)}`)
}
})会话管理集成
export default defineCallbackEventHandler({
onSuccess: async (event, { userInfo, tokenData }) => {
// 创建用户会话
const session = await createUserSession({
userId: userInfo.id,
email: userInfo.email,
accessToken: tokenData.access_token
})
// 设置会话 cookie
setCookie(event, 'session', session.id, {
httpOnly: true,
secure: true,
maxAge: 86400 // 24 小时
})
}
})数据库集成
export default defineCallbackEventHandler({
onSuccess: async (event, { providerName, userInfo, tokenData }) => {
// 查找或创建用户
let user = await findUserByEmail(userInfo.email)
if (!user) {
user = await createUser({
email: userInfo.email,
name: userInfo.name,
avatar: userInfo.avatar_url,
provider: providerName
})
}
// 更新或创建 OAuth 连接
await upsertOAuthConnection({
userId: user.id,
provider: providerName,
providerId: userInfo.id.toString(),
accessToken: tokenData.access_token
})
}
})🧪 开发和测试
运行示例项目
# 安装依赖
npm install
# 启动开发服务器
npm run dev访问 http://localhost:3000 查看示例应用。
测试
# 运行测试
npm run test
# 监听模式
npm run test:watch🤝 贡献
欢迎提交 Issue 和 Pull Request!
