mcpField
N
nodeops-auth

nodeops-auth

github.com/nodeops-app开发2564 次安装5 周前更新
代码仓库

关于 nodeops-auth

nodeops-auth 是面向现有 Next.js App Router 项目的设置技能,用于接入 NodeOps PKCE OAuth。它检查项目结构并按需创建路由、回调页和环境配置,同时避免覆盖已完成的设置。

主要功能

  1. 01检测 Next.js 与 App Router 项目
  2. 02按包管理器安装 OAuth 集成包
  3. 03创建认证 API 路由与回调页
  4. 04将 AuthProvider 接入根布局
  5. 05管理环境变量与忽略规则
  6. 06检查 Docker 部署配置

适用场景

  1. 01为现有 Next.js 应用添加 NodeOps 登录
  2. 02为 OAuth 回调配置重定向页面
  3. 03为容器部署核对构建时环境变量

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nodeops-app/skills --skill nodeops-auth

安装后在 Claude Code 中输入/nodeops-auth确认已加载。

详细介绍

NodeOps Auth 设置

为现有的 Next.js(App Router)项目添加 NodeOps PKCE OAuth。

前置条件

开始之前,请确认项目兼容:

  • 必须使用 App Router:检查是否存在 app/ 目录。如果只存在 pages/,请停止并告知用户:“此技能仅支持 Next.js App Router。你的项目使用的是 Pages Router。”
  • 必须使用 Next.js:检查 package.json 中的依赖项是否包含 next。如果没有,请停止并告知用户这是一个仅适用于 Next.js 的软件包。

幂等性

执行每个步骤前,先检查相应工作是否已完成。跳过已完成的步骤:

  • 如果 package.json 的依赖项中已包含 @nodeops-createos/integration-oauth,则跳过安装。
  • 如果 app/api/auth/me/route.ts 和 app/api/auth/token/route.ts 已存在,则跳过路由创建。
  • 如果布局中已导入 @nodeops-createos/integration-oauth 的 AuthProvider,则跳过封装。
  • 如果 app/callback/page.tsx(或 .jsx)已存在,则跳过回调页面创建。
  • 如果 .env.example 已存在且包含 NODEOPS_,则跳过环境文件创建。

步骤

  1. 检测项目设置 — 读取 package.json 并检查锁文件:

    • 包管理器:如果存在 pnpm-lock.yaml,则使用 pnpm;如果存在 yarn.lock,则使用 yarn;否则使用 npm。
    • TypeScript:如果存在 tsconfig.json,则使用 .ts/.tsx 扩展名;否则使用 .js/.jsx。
    • 确认 app/ 目录存在(App Router)。如果只存在 pages/,请停止。
    • 确认依赖项中包含 next。如果没有,请停止。
  2. 安装软件包 — 运行相应的安装命令:

    • npm:npm install @nodeops-createos/integration-oauth
    • pnpm:pnpm add @nodeops-createos/integration-oauth
    • yarn:yarn add @nodeops-createos/integration-oauth
    • 如果安装失败:检查用户是否可以访问网络,以及是否可以访问注册表。如果持续失败,建议手动运行该命令。
  3. 创建 API 路由 — 创建两个独立的路由文件,并按需创建目录:

    app/api/auth/me/route.ts(或 .js):

    export { GET } from '@nodeops-createos/integration-oauth/server/me';
    

    app/api/auth/token/route.ts(或 .js):

    export { POST } from '@nodeops-createos/integration-oauth/server/token';
    
  4. 使用 AuthProvider 封装布局 — 读取根布局文件。它可能是 app/layout.tsx、app/layout.jsx、app/layout.js 或 app/layout.ts。找到实际存在的文件。

    • 在文件顶部添加导入语句:
      import { AuthProvider } from '@nodeops-createos/integration-oauth';
      
    • 在 <body> 标签中找到 {children}。使用 <AuthProvider> 将其封装:
      <AuthProvider>{children}</AuthProvider>
      
    • 不要在布局中添加 "use client"。 AuthProvider 内部已经标记为 "use client",从 Server Component 布局中导入也能正常使用。
    • 如果布局中已有其他 Provider(例如 ThemeProvider、QueryClientProvider),请将 <AuthProvider> 与它们并列嵌套。不要移除或替换现有 Provider。
    • 如果 {children} 没有直接位于 <body> 中(例如,它位于包装用的 div 或 fragment 中),请在 {children} 出现的位置进行封装。
    • 如果不存在布局文件,请停止并告知用户先创建根布局。
  5. 创建回调页面 — 询问用户:“登录后应将用户重定向到哪里?(默认:/dashboard)”。将用户的回答用作 redirectTo 值。然后创建 app/callback/page.tsx(或 .jsx):

    "use client";
    import { useCallbackHandler } from "@nodeops-createos/integration-oauth";
    
    export default function Callback() {
      const { loading, error } = useCallbackHandler({ redirectTo: "/dashboard" });
    
      if (loading) return (
        <div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }}>
          <p>Signing in...</p>
        </div>
      );
      if (error) return <p>Login failed: {error}</p>;
      return null;
    }
    
  6. 创建 .env.example — 在项目根目录创建此文件:

    # ── Client-side (exposed to browser via NEXT_PUBLIC_ prefix) ──────────────────
    NEXT_PUBLIC_NODEOPS_AUTH_URL=https://id.nodeops.network/oauth2/auth
    NEXT_PUBLIC_NODEOPS_CLIENT_ID=your_client_id_here
    NEXT_PUBLIC_NODEOPS_REDIRECT_URI=http://localhost:3000/callback
    NEXT_PUBLIC_NODEOPS_SCOPES=offline_access offline openid
    
    # ── Server-side only (never sent to browser) ──────────────────────────────────
    NODEOPS_CLIENT_SECRET=your_client_secret_here
    NODEOPS_TOKEN_URL=https://id.nodeops.network/oauth2/token
    NODEOPS_USERINFO_URL=https://autogen-v2-api.nodeops.network/v1/users/me
    
  7. 创建 .env.local — 如果 .env.local 不存在,请将 .env.example 复制到 .env.local,并提醒用户使用其 NodeOps 开发者门户中的凭据填写 NEXT_PUBLIC_NODEOPS_CLIENT_ID 和 NODEOPS_CLIENT_SECRET。如果 .env.local 已存在,则仅追加缺少的 NODEOPS_ 变量,不要覆盖现有值。

  8. 检查 .gitignore — 读取 .gitignore(如果存在)。如果其中未列出 .env.local,请将其添加进去,以防泄露机密信息。同时确保已列出 .env。如果不存在 .gitignore,请创建一个,至少包含:

    .env
    .env.local
    
  9. Docker/容器部署 — 检查项目根目录中是否存在 Dockerfile。如果存在,请验证它是否正确处理 NodeOps 环境变量;如果没有,请提醒用户。如果用户询问 Docker 或部署,请创建或更新 Dockerfile。

    重要:Next.js 会在构建时将 NEXT_PUBLIC_* 变量嵌入 JS 包中。必须在 RUN npm run build 之前,将它们设置为 Dockerfile 中的 ENV 或 ARG。仅在运行时设置不起作用 — 包中会包含 undefined。

    这两类变量:

    变量所需时机原因
    NEXT_PUBLIC_NODEOPS_AUTH_URL构建时内嵌到客户端 JS 包中
    NEXT_PUBLIC_NODEOPS_CLIENT_ID构建时内嵌到客户端 JS 包中
    NEXT_PUBLIC_NODEOPS_REDIRECT_URI构建时内嵌到客户端 JS 包中
    NEXT_PUBLIC_NODEOPS_SCOPES构建时内嵌到客户端 JS 包中
    NODEOPS_CLIENT_SECRET仅运行时API 路由每次请求时读取
    NODEOPS_TOKEN_URL仅运行时API 路由每次请求时读取
    NODEOPS_USERINFO_URL仅运行时API 路由每次请求时读取

    CreateOS 注意事项:存在 Dockerfile 时,CreateOS 会使用它。仅使用单阶段 Dockerfile — 在此平台上,包含 COPY --from=builder 的多阶段构建会失败。完全移除 Dockerfile,即可改用 CreateOS 默认的安装/运行命令。有关 NEXT_PUBLIC_* 变量的运行时配置解决方法,请参阅 CreateOS 部分(步骤 10)。

    Dockerfile 示例(单阶段,兼容 CreateOS):

    FROM node:20-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    
    COPY . .
    
    # NEXT_PUBLIC_* must be present at build time — they get baked into the JS bundle
    ARG NEXT_PUBLIC_NODEOPS_AUTH_URL=https://id.nodeops.network/oauth2/auth
    ARG NEXT_PUBLIC_NODEOPS_CLIENT_ID
    ARG NEXT_PUBLIC_NODEOPS_REDIRECT_URI
    ARG NEXT_PUBLIC_NODEOPS_SCOPES=offline_access offline openid
    
    ENV NEXT_PUBLIC_NODEOPS_AUTH_URL=$NEXT_PUBLIC_NODEOPS_AUTH_URL
    ENV NEXT_PUBLIC_NODEOPS_CLIENT_ID=$NEXT_PUBLIC_NODEOPS_CLIENT_ID
    ENV NEXT_PUBLIC_NODEOPS_REDIRECT_URI=$NEXT_PUBLIC_NODEOPS_REDIRECT_URI
    ENV NEXT_PUBLIC_NODEOPS_SCOPES=$NEXT_PUBLIC_NODEOPS_SCOPES
    
    # Server-side vars — only needed at runtime, read per-request by API routes
    ENV NODEOPS_CLIENT_SECRET=""
    ENV NODEOPS_TOKEN_URL=https://id.nodeops.network/oauth2/token
    ENV NODEOPS_USERINFO_URL=https://autogen-v2-api.nodeops.network/v1/users/me
    
    RUN npm run build
    
    EXPOSE 3000
    CMD ["npm", "start"]
    

    同时确保 .dockerignore 排除了 .env.local:

    .env
    .env.local
    node_modules
    .next
    

    如果项目部署到 Vercel 或类似平台:无需 Dockerfile — 这些平台会在构建前自动注入环境变量。只需提醒用户在其平台的控制面板中添加这些变量。

  10. CreateOS/构建后注入的平台 — 存在 Dockerfile 时,CreateOS 会使用它,但会在构建步骤之后注入环境变量。这意味着即使在 Dockerfile 中使用 ARG/ENV,NEXT_PUBLIC_* 变量在构建时仍为 undefined。请使用以下运行时配置解决方法,或完全移除 Dockerfile,以改用 CreateOS 默认的安装/运行命令。

    软件包会自动处理的内容(v1.x+)

    如果包中缺少 NEXT_PUBLIC_* 变量,来自 @nodeops-createos/integration-oauth v1.x+ 的 AuthProvider 会在运行时自动获取 /api/config。无需额外设置 — 只需确保 API 路由存在(见下方步骤 10a)。

    如果使用较旧的软件包版本,请手动添加:

    10a. 创建 app/api/config/route.ts(或 .js):

    import { NextResponse } from 'next/server';
    
    export const dynamic = 'force-dynamic';
    
    export async function GET() {
      return NextResponse.json({
        NEXT_PUBLIC_NODEOPS_AUTH_URL:     process.env.NEXT_PUBLIC_NODEOPS_AUTH_URL     || 'https://id.nodeops.network/oauth2/auth',
        NEXT_PUBLIC_NODEOPS_CLIENT_ID:    process.env.NEXT_PUBLIC_NODEOPS_CLIENT_ID    || '',
        NEXT_PUBLIC_NODEOPS_REDIRECT_URI: process.env.NEXT_PUBLIC_NODEOPS_REDIRECT_URI || '',
        NEXT_PUBLIC_NODEOPS_SCOPES:       process.env.NEXT_PUBLIC_NODEOPS_SCOPES       || 'offline_access offline openid',
      });
    }
    

    此路由会在运行时从服务器环境中读取 NEXT_PUBLIC_* 变量(此时这些变量确实可用),并通过 JSON 端点将它们提供给客户端。

    10b. 创建 components/EnvBootstrap.tsx(或 .jsx):

    "use client";
    import { useEffect, useState } from "react";
    export default function EnvBootstrap({ children }: { children: React.ReactNode }) {
      const [ready, setReady] = useState(
        // 如果变量已写入(例如本地开发),则跳过获取
        typeof window !== "undefined" && !!process.env.NEXT_PUBLIC_NODEOPS_CLIENT_ID
      );
    
      useEffect(() => {
        if (ready) return;
        fetch("/api/config")
          .then((r) => r.json())
          .then((env) => {
            // 修补 process.env,让 AuthProvider 能读取这些变量
            Object.assign(process.env, env);
            setReady(true);
          })
          .catch((err) => {
            console.error("Failed to load runtime config:", err);
            setReady(true); // 仍然渲染,以显示错误状态
          });
      }, [ready]);
    
      if (!ready) return null;
      return <>{children}</>;
    }
    

    10c. 更新根布局,用 EnvBootstrap 包裹 AuthProvider:

    import { AuthProvider } from '@nodeops-createos/integration-oauth';
    import EnvBootstrap from '@/components/EnvBootstrap';
    
    // 在 <body> 内:
    <EnvBootstrap>
      <AuthProvider>{children}</AuthProvider>
    </EnvBootstrap>
    

    这样可以确保先从服务端获取环境变量并写入 process.env,然后再由客户端初始化 AuthProvider。

  11. 显示摘要 — 打印清晰的摘要:

    • 创建/修改的文件(逐一列出)
    • 跳过的文件(如果文件已存在)
    • 提醒用户填写 2 个必需的环境变量:NEXT_PUBLIC_NODEOPS_CLIENT_ID 和 NODEOPS_CLIENT_SECRET
    • 如果存在 Dockerfile,提醒用户必须在 Dockerfile 中运行 npm run build 之前设置 NEXT_PUBLIC_* 变量
    • 展示如何在任意页面使用这些钩子:
      import { useAuth, useUser } from '@nodeops-createos/integration-oauth';
      
      const { isAuthenticated, login, logout, loading, authError } = useAuth();
      const { user } = useUser();
      

评论

支持 Markdown