mcpField
A
authentication

authentication

github.com/mgd34msu安全656 次安装10 周前更新
代码仓库

关于 authentication

authentication 是用于在不同 Web 技术栈中规划和实现身份验证的技能。它引导检查现有实现、按框架配置、安全验证和测试,并根据项目调整流程,而非指定单一库。

主要功能

  1. 01检测现有身份验证模式与技术栈
  2. 02规划框架专属身份验证文件
  3. 03指导会话、OAuth 与路由保护
  4. 04检查密钥和安全设置
  5. 05生成测试场景并运行清单

适用场景

  1. 01添加登录与注册流程
  2. 02保护路由和 API 端点
  3. 03集成 OAuth 或会话管理
  4. 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)
  • 令牌刷新机制
  • 密码重置流程

前提条件

开始之前:

  1. 了解项目框架(Next.js、Remix、Express 等)
  2. 规划好数据库架构(如果使用基于数据库的身份验证)
  3. 确定身份验证方案(托管服务还是可自托管)
  4. 能够访问环境变量配置

工作流步骤

第 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 步:规划实现

根据框架和决策树,规划要创建或修改的文件:

常见所需文件:

  1. 中间件(middleware.ts、auth.middleware.ts)

    • 拦截请求
    • 验证身份验证状态
    • 重定向未经身份验证的用户
  2. 身份验证工具函数(lib/auth.ts、utils/auth.ts)

    • 创建和验证会话
    • 生成和验证令牌
    • 密码哈希(bcrypt、argon2)
  3. 身份验证 API 路由(/api/auth/login、/api/auth/signup、/api/auth/logout)

    • 处理身份验证请求
    • 设置会话 Cookie
    • 返回身份验证状态
  4. 受保护路由包装器(withAuth、requireAuth)

    • 高阶组件或服务端工具函数
    • 在渲染前检查身份验证状态
    • 重定向或返回 401
  5. 客户端钩子(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_SECRET
  • DATABASE_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(所有检查均通过)

手动测试清单:

  1. 注册新用户
  2. 确认数据库中的密码已哈希
  3. 使用凭据登录
  4. 访问受保护路由(应成功)
  5. 登出
  6. 访问受保护路由(应重定向到登录页)
  7. 测试 OAuth 流程(如果已实现)
  8. 确认会话在重新加载页面后仍然有效
  9. 测试令牌过期和刷新

各框架的常见模式

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 域名不匹配

解决方法:

  1. 检查身份验证代码中的 Cookie 配置
  2. 确认响应中包含 Cookie:precision_exec: { cmd: "curl -v localhost:3000/api/auth/login" }
  3. 确保中间件能正确读取 Cookie
“服务器重启后 JWT 令牌无效”

可能原因:

  • JWT_SECRET 在重启期间发生变化
  • .env 文件中未设置密钥
  • 不同环境使用了不同的密钥

解决方法:

  1. 将 JWT_SECRET 移至 .env:JWT_SECRET=<random-256-bit-hex>
  2. 使用以下命令生成:openssl rand -hex 32
  3. 切勿将 .env 提交到 git
“OAuth 回调因 redirect_uri_mismatch 失败”

可能原因:

  • OAuth 提供商的控制面板中未将回调 URL 加入允许列表
  • http 与 https 不匹配
  • 缺少端口号

解决方法:

  1. 检查 OAuth 提供商设置
  2. 按错误中显示的 URL 原样添加回调 URL
  3. 对于本地开发,请使用 http://localhost:3000/api/auth/callback/google(示例)
“受保护的路由未重定向”

可能原因:

  • 中间件配置不正确
  • Matcher 模式与路由不匹配
  • 会话验证静默失败

解决方法:

  1. 检查 middleware.ts 中的 config.matcher
  2. 在中间件中添加日志,以确认其是否运行
  3. 独立测试会话验证

实施后的后续步骤

  1. 添加基于角色的访问控制(RBAC):

    • 在 User 模型中添加 role 字段
    • 创建权限检查工具
    • 保护管理路由
  2. 实现密码重置:

    • 生成重置令牌
    • 发送包含重置链接的电子邮件
    • 验证令牌并更新密码
  3. 添加电子邮件验证:

    • 注册时生成验证令牌
    • 发送验证电子邮件
    • 验证令牌并将用户标记为已验证
  4. 设置刷新令牌:

    • 颁发短期访问令牌(15 min)
    • 颁发长期刷新令牌(7 days)
    • 使用时轮换刷新令牌
  5. 添加审计日志:

    • 记录所有登录尝试(成功和失败)
    • 跟踪 IP 地址和用户代理
    • 监控可疑活动

总结

此工作流提供:

  • 与框架无关的身份验证实现
  • 以安全为先并包含验证的方案
  • 与 GoodVibes 精确工具集成
  • 通过脚本进行自动化验证
  • 错误处理与故障排查

请按顺序完成每个步骤,并使用精确工具执行所有文件操作和验证。

评论

支持 Markdown