关于 authentication
authentication 是用于在不同 Web 技术栈中规划和实现身份验证的技能。它引导检查现有实现、按框架配置、安全验证和测试,并根据项目调整流程,而非指定单一库。
主要功能
- 01检测现有身份验证模式与技术栈
- 02规划框架专属身份验证文件
- 03指导会话、OAuth 与路由保护
- 04检查密钥和安全设置
- 05生成测试场景并运行清单
适用场景
- 01添加登录与注册流程
- 02保护路由和 API 端点
- 03集成 OAuth 或会话管理
- 04审查身份验证实现
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mgd34msu/ goodvibes-plugin --skill authentication安装后在 Claude Code 中输入/authentication确认已加载。
附带文件references/decision-tree.mdscripts/auth-checklist.sh
详细介绍
资源
scripts/
auth-checklist.sh
references/
decision-tree.md
身份验证实现工作流
此技能会统筹从调研到测试的完整身份验证实现流程。它以统一的工作流取代特定于库的技能(clerk、nextauth、lucia、auth0、firebase-auth、supabase-auth、passport),并根据你的技术栈进行调整。
何时使用此技能
在实现以下功能时使用:
- 用户登录和注册流程
- 会话管理(Cookie、JWT、服务端会话)
- OAuth 集成(Google、GitHub 等)
- 受保护的路由和 API 端点
- 基于中间件的身份验证
- 基于角色的访问控制(RBAC)
- 令牌刷新机制
- 密码重置流程
前提条件
开始之前:
- 了解项目框架(Next.js、Remix、Express 等)
- 规划好数据库架构(如果使用基于数据库的身份验证)
- 确定身份验证方案(托管服务还是可自托管)
- 能够访问环境变量配置
工作流步骤
第 1 步:调研
使用 discover 了解现有的身份验证模式:
discover:
queries:
- id: existing-auth
type: grep
pattern: "(useAuth|getSession|withAuth|requireAuth|protect|authenticate)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: middleware-files
type: glob
patterns:
- "**/middleware.{ts,js}"
- "**/auth/**/*.{ts,js}"
- "**/_middleware.{ts,js}"
- id: session-handling
type: grep
pattern: "(session|jwt|token|cookie)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: protected-routes
type: grep
pattern: "(protected|private|requireAuth|withAuth)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_only
需要查找的内容:
- 现有的身份验证钩子、工具函数或中间件
- 会话存储机制(Cookie、localStorage、服务端)
- 受保护路由模式
- 身份验证提供方的配置(如果使用第三方服务)
决策点: 如果已经部分实现了身份验证,请先阅读现有文件以了解其模式,再进行扩展。
第 2 步:检测技术栈
使用 detect_stack 确定框架并识别身份验证方案:
detect_stack:
path: "."
框架检测:
- Next.js(App Router):使用 middleware.ts + Server Actions + Cookie
- Next.js(Pages Router):使用 getServerSideProps + API 路由 + NextAuth
- Remix:使用 loader/action 身份验证 + 会话 Cookie
- Express/Fastify:使用中间件 + 会话存储
- tRPC:使用上下文 + 中间件
- GraphQL:使用上下文 + 指令
参考决策树: 阅读 references/decision-tree.md,根据框架和需求,在托管服务(Clerk、Auth0)、可自托管(NextAuth、Lucia)或无服务器方案(Supabase Auth)之间进行选择。
第 3 步:规划实现
根据框架和决策树,规划要创建或修改的文件:
常见所需文件:
-
中间件(
middleware.ts、auth.middleware.ts)- 拦截请求
- 验证身份验证状态
- 重定向未经身份验证的用户
-
身份验证工具函数(
lib/auth.ts、utils/auth.ts)- 创建和验证会话
- 生成和验证令牌
- 密码哈希(bcrypt、argon2)
-
身份验证 API 路由(
/api/auth/login、/api/auth/signup、/api/auth/logout)- 处理身份验证请求
- 设置会话 Cookie
- 返回身份验证状态
-
受保护路由包装器(
withAuth、requireAuth)- 高阶组件或服务端工具函数
- 在渲染前检查身份验证状态
- 重定向或返回 401
-
客户端钩子(
useAuth、useSession)- 获取当前用户
- 管理客户端身份验证状态
- 触发登录或登出
特定于框架的模式:
Next.js App Router:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('session')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*']
};
Remix:
// app/utils/session.server.ts
import { createCookieSessionStorage } from '@remix-run/node';
const { getSession, commitSession, destroySession } =
createCookieSessionStorage({
cookie: {
name: '__session',
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secrets: [process.env.SESSION_SECRET],
sameSite: 'lax'
}
});
export { getSession, commitSession, destroySession };
Express:
// middleware/auth.ts
import jwt from 'jsonwebtoken';
import type { Request, Response, NextFunction } from 'express';
export function requireAuth(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace(/^bearer\s+/i, '');
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
req.user = payload;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
第 4 步:编写配置和核心文件
使用 precision_write 的批处理模式创建身份验证基础设施:
precision_write:
files:
- path: "middleware.ts"
content: |
# Framework-specific middleware (see patterns above)
- path: "lib/auth.ts"
content: |
# Session validation, token generation
- path: "app/api/auth/login/route.ts"
content: |
# Login endpoint implementation
- path: "app/api/auth/signup/route.ts"
content: |
# Sign-up endpoint with validation
- path: "app/api/auth/logout/route.ts"
content: |
# Logout and session cleanup
verbosity: minimal
重要:不得使用占位符
- 实现完整的验证(zod、yup 等)
- 包含适当的错误处理
- 使用 bcrypt/argon2 对密码进行哈希处理
- 使用安全的会话配置
- 在适用时添加 CSRF 防护
第 5 步:安装依赖项
使用 precision_exec 安装所需的软件包:
precision_exec:
commands:
# For JWT-based auth
- cmd: "npm install jsonwebtoken bcryptjs"
- cmd: "npm install -D @types/jsonwebtoken @types/bcryptjs"
# For session-based auth
- cmd: "npm install express-session connect-redis"
- cmd: "npm install -D @types/express-session"
# For managed services
- cmd: "npm install @clerk/nextjs" # Clerk
- cmd: "npm install next-auth" # NextAuth
- cmd: "npm install better-auth" # Better Auth (replaces deprecated Lucia)
verbosity: minimal
运行数据库迁移(如有需要):
precision_exec:
commands:
- cmd: "npx prisma migrate dev --name add_user_auth"
timeout_ms: 60000
- cmd: "npx prisma generate"
verbosity: standard
步骤 6:安全验证
使用 analysis-engine 工具验证安全性:
1. 扫描硬编码密钥:
scan_for_secrets:
paths:
- "lib/auth.ts"
- "app/api/auth/**/*.ts"
- "middleware.ts"
预期结果: 未发现任何密钥。所有 API 密钥、JWT 密钥和凭据都必须存放在 .env 文件中。
如果发现密钥:
- 移至
.env或.env.local - 使用
process.env.VAR_NAME进行访问 - 如果尚未添加,则将其加入
.gitignore
2. 审核环境变量:
env_audit:
check_documented: true
预期结果: 所有与身份验证相关的环境变量都记录在 .env.example 或 README 中。
必需变量(通常包括):
JWT_SECRET或SESSION_SECRETDATABASE_URL(如果使用数据库)- OAuth 凭据(
GOOGLE_CLIENT_ID、GITHUB_CLIENT_SECRET等) NEXTAUTH_URL和NEXTAUTH_SECRET(用于 NextAuth)
3. 验证实现:
# Use precision_grep to validate critical security patterns
precision_grep:
queries:
- id: password_hashing
pattern: "bcrypt|argon2|hashPassword"
path: "lib"
glob: "**/*.ts"
- id: httpOnly_cookies
pattern: "httpOnly.*true|httpOnly:\s*true"
path: "."
glob: "**/*.ts"
- id: csrf_protection
pattern: "csrf|CsrfToken|verifyCsrfToken"
path: "."
glob: "**/*.ts"
output:
format: "count_only"
步骤 7:实现受保护路由
创建路由保护工具:
服务端保护(Next.js App Router):
// lib/auth.ts
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
export async function requireAuth() {
const cookieStore = await cookies();
const session = cookieStore.get('session')?.value;
if (!session) {
redirect('/login');
}
const user = await validateSession(session);
if (!user) {
redirect('/login');
}
return user;
}
客户端钩子(React):
// hooks/useAuth.ts
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
export function useAuth(options?: { redirectTo?: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const router = useRouter();
useEffect(() => {
fetch('/api/auth/me')
.then(res => res.ok ? res.json() : null)
.then(data => {
if (!data && options?.redirectTo) {
router.push(options.redirectTo);
} else {
setUser(data);
}
})
.finally(() => setLoading(false));
}, [options?.redirectTo, router]);
return { user, loading };
}
应用到路由:
使用 precision_edit 为现有路由添加身份验证检查:
precision_edit:
files:
- path: "app/dashboard/page.tsx"
edits:
- find: "export default function DashboardPage()"
replace: |
export default async function DashboardPage() {
const user = await requireAuth();
hints:
near_line: 1
步骤 8:测试实现
使用 suggest_test_cases 生成特定于身份验证的测试场景:
suggest_test_cases:
file: "lib/auth.ts"
category: "authentication"
预期测试用例:
- 使用正确凭据成功登录
- 使用错误密码登录失败
- 使用有效数据注册
- 使用重复的电子邮件注册
- 受保护路由将未通过身份验证的用户重定向
- 刷新会话令牌
- 登出后清除会话
- 验证 CSRF 令牌
- 密码重置流程
运行验证脚本:
bash scripts/auth-checklist.sh .
预期退出代码: 0(所有检查均通过)
手动测试清单:
- 注册新用户
- 确认数据库中的密码已哈希
- 使用凭据登录
- 访问受保护路由(应成功)
- 登出
- 访问受保护路由(应重定向到登录页)
- 测试 OAuth 流程(如果已实现)
- 确认会话在重新加载页面后仍然有效
- 测试令牌过期和刷新
各框架的常见模式
Next.js(App Router)
会话管理:
- 使用 'next/headers' 中的 cookies()
- 设置 httpOnly、secure、sameSite Cookie
- 在 middleware.ts 和 Server Components 中进行验证
受保护路由:
- 服务端:在 page/layout 中使用 await requireAuth()
- 客户端:使用带有 redirectTo 的 useAuth() 钩子
- API 路由:在路由处理程序中检查 Cookie
OAuth:
- 使用 NextAuth 简化流程
- 或使用重定向 URI 手动实现 OAuth 流程
Remix
会话管理:
- 使用 createCookieSessionStorage
- 在 loaders 中进行验证
- 在 actions 中提交会话
受保护路由:
- 在 loader 中检查会话;如果未通过身份验证,则抛出 redirect()
- 始终使用 getSession() 工具
OAuth:
- 使用 remix-auth 策略
- 在专用路由中处理回调
Express/Fastify
会话管理:
- 使用 express-session 和 Redis 存储
- 或在 Authorization 标头中使用 JWT 令牌
受保护路由:
- 中间件函数:requireAuth、optionalAuth
- 应用于特定路由或全局应用
OAuth:
- 使用 passport.js 策略
- 配置序列化/反序列化用户
错误处理
身份验证失败时遵循错误恢复协议:
登录失败
try {
const user = await validateCredentials(email, password);
await createSession(user.id);
return { success: true };
} catch (err) {
if (err instanceof InvalidCredentialsError) {
// Don't leak whether email exists
return { error: 'Invalid email or password' };
}
if (err instanceof UserLockedError) {
return { error: 'Account locked. Contact support.' };
}
throw err; // Unexpected error
}
会话验证失败
export async function validateSession(token: string) {
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
return await getUserById(payload.userId);
} catch (err) {
if (err instanceof jwt.TokenExpiredError) {
return null; // Let caller handle (refresh or re-login)
}
if (err instanceof jwt.JsonWebTokenError) {
return null; // Invalid token
}
throw err; // Unexpected error
}
}
数据库错误
try {
const user = await db.user.create({
data: { email, passwordHash }
});
} catch (err) {
if (err.code === 'P2002') {
// Prisma unique constraint violation
return { error: 'Email already registered' };
}
throw err;
}
安全清单
在标记实现完成前:
- 使用 bcrypt(cost 10+)或 argon2 对密码进行哈希
- 会话令牌应为随机值(crypto.randomBytes)或已签名的 JWT
- Cookie 应设置 httpOnly、secure(生产环境中)和 sameSite: 'lax' 或 'strict'
- 启用 CSRF 防护(基于 Cookie 的身份验证)
- 对登录/注册端点进行速率限制
- 验证所有身份验证端点的输入
- 错误消息中不包含敏感数据
- 在 .env.example 中记录环境变量
- 源代码中没有硬编码密钥
- 配置会话过期时间(通常为 1–7 天)
- 登出时清除所有身份验证令牌/会话
- 将 OAuth 重定向 URI 列入白名单
参考资料
references/decision-tree.md- 托管、自托管与无服务器方案对比.goodvibes/memory/patterns.json- 项目特定的身份验证模式scripts/auth-checklist.sh- 自动化验证脚本
故障排查
“请求之间会话未持久化”
可能原因:
- Cookie 未设置(检查响应头)
- httpOnly 阻止客户端访问(这是预期行为)
- sameSite: 'strict' 阻止跨源请求(请使用 'lax')
- Cookie 域名不匹配
解决方法:
- 检查身份验证代码中的 Cookie 配置
- 确认响应中包含 Cookie:
precision_exec: { cmd: "curl -v localhost:3000/api/auth/login" } - 确保中间件能正确读取 Cookie
“服务器重启后 JWT 令牌无效”
可能原因:
- JWT_SECRET 在重启期间发生变化
- .env 文件中未设置密钥
- 不同环境使用了不同的密钥
解决方法:
- 将 JWT_SECRET 移至 .env:
JWT_SECRET=<random-256-bit-hex> - 使用以下命令生成:
openssl rand -hex 32 - 切勿将 .env 提交到 git
“OAuth 回调因 redirect_uri_mismatch 失败”
可能原因:
- OAuth 提供商的控制面板中未将回调 URL 加入允许列表
- http 与 https 不匹配
- 缺少端口号
解决方法:
- 检查 OAuth 提供商设置
- 按错误中显示的 URL 原样添加回调 URL
- 对于本地开发,请使用 http://localhost:3000/api/auth/callback/google(示例)
“受保护的路由未重定向”
可能原因:
- 中间件配置不正确
- Matcher 模式与路由不匹配
- 会话验证静默失败
解决方法:
- 检查 middleware.ts 中的 config.matcher
- 在中间件中添加日志,以确认其是否运行
- 独立测试会话验证
实施后的后续步骤
-
添加基于角色的访问控制(RBAC):
- 在 User 模型中添加
role字段 - 创建权限检查工具
- 保护管理路由
- 在 User 模型中添加
-
实现密码重置:
- 生成重置令牌
- 发送包含重置链接的电子邮件
- 验证令牌并更新密码
-
添加电子邮件验证:
- 注册时生成验证令牌
- 发送验证电子邮件
- 验证令牌并将用户标记为已验证
-
设置刷新令牌:
- 颁发短期访问令牌(15 min)
- 颁发长期刷新令牌(7 days)
- 使用时轮换刷新令牌
-
添加审计日志:
- 记录所有登录尝试(成功和失败)
- 跟踪 IP 地址和用户代理
- 监控可疑活动
总结
此工作流提供:
- 与框架无关的身份验证实现
- 以安全为先并包含验证的方案
- 与 GoodVibes 精确工具集成
- 通过脚本进行自动化验证
- 错误处理与故障排查
请按顺序完成每个步骤,并使用精确工具执行所有文件操作和验证。