NextJs 14 App Router SSR路由中Amplify GraphQL无凭证问题求助
你遇到的核心问题是:Stripe 发起的 Webhook 请求是从 Stripe 服务器直接发送到你的 Next.js Route Handler,完全不包含用户浏览器的认证 Cookie。不管你怎么配置 Amplify 的 SSR 模式,这里都拿不到用户的凭证——因为这个请求和用户的前端会话没有关联。
之前尝试的 Amplify SSR 配置(比如ssr: true)只适用于用户发起的前端请求(比如页面渲染、客户端 API 调用),但 Webhook 属于服务端到服务端的请求,不会携带用户的 Cookie,所以必然会出现"No Credentials"错误。
解决方案:使用服务端级别的授权调用 AppSync
针对 Webhook 场景,你需要绕过用户级别的认证,用服务端凭证直接调用 AppSync。推荐两种可行方案:
方案一:使用 IAM 角色授权(生产环境推荐)
步骤1:配置 Amplify 服务端客户端(基于 IAM)
修改你的amplifyServerUtils.ts,创建一个用 IAM 初始化的客户端,不需要依赖用户 Cookie:
// amplifyServerUtils.ts import { Amplify } from 'aws-amplify'; import { generateClient } from 'aws-amplify/api'; import amplifyConfig from '../amplifyconfiguration.json'; import { defaultProvider } from '@aws-sdk/credential-provider-node'; // 初始化 Amplify 服务端配置 Amplify.configure({ ...amplifyConfig, Auth: { credentialsProvider: defaultProvider() // 使用 Node.js 默认凭证链(本地用~/.aws/credentials,生产用ECS/EKS角色) } }, { ssr: true }); // 创建服务端专用的 GraphQL 客户端 export const serverIAMClient = generateClient();
步骤2:更新 AppSync API 权限
在 AppSync 控制台中,修改createTransaction mutation 的权限规则,允许你的 IAM 角色执行该操作:
- 打开 AppSync 控制台 → 你的 API → 架构 → 找到
createTransaction - 添加如下权限规则(替换为你的 IAM 角色 ARN):
type Transaction @model @auth(rules: [ { allow: private, provider: iam }, // 允许IAM角色调用 { allow: owner, ownerField: "userId" } // 保留用户级别的所有者权限 ]) { // 你的 Transaction 字段... }
步骤3:在 Route Handler 中使用服务端客户端
修改route.ts中的 GraphQL 请求部分:
// 在 payment_intent.succeeded 分支中替换原请求代码 try { const result = await serverIAMClient.graphql({ query: createTransaction, variables: { transaction: transactionInput }, }); console.log("createTransaction result transactionId = ", result.data.createTransaction?.transactionId); } catch (error) { console.log("createTransaction failed with error: ", error); }
方案二:使用 API Key 授权(测试/快速验证用)
如果只是快速验证功能,可以用 AppSync 的 API Key 直接调用,不需要 IAM 配置:
步骤1:修改服务端客户端配置
// amplifyServerUtils.ts import { Amplify } from 'aws-amplify'; import { generateClient } from 'aws-amplify/api'; import amplifyConfig from '../amplifyconfiguration.json'; Amplify.configure({ ...amplifyConfig, API: { GraphQL: { apiKey: process.env.APPSYNC_API_KEY // 从环境变量获取API Key } } }, { ssr: true }); export const serverAPIKeyClient = generateClient();
步骤2:更新 AppSync 权限
确保createTransaction允许 API Key 访问:
type Transaction @model @auth(rules: [ { allow: apiKey }, // 允许API Key调用 { allow: owner, ownerField: "userId" } ]) { // 字段... }
步骤3:在 Route Handler 中使用该客户端
和方案一类似,替换为serverAPIKeyClient即可。
额外注意点:获取真实的 userId
你当前代码中userId: '1234'是硬编码的,正确的做法是:
- 在前端创建 Payment Intent时,把当前用户的 ID 存入 Payment Intent 的
metadata中:
// 前端代码(比如 checkout 页面) const { data } = await stripe.createPaymentIntent({ amount: 1000, currency: 'usd', metadata: { userId: user.id // 从 Amplify Auth 获取当前用户ID } });
- 在 Webhook 中从 Payment Intent 取出
metadata.userId:
// route.ts 中 payment_intent.succeeded 分支 const userId = paymentIntentSucceeded.metadata.userId; const transactionInput: TransactionInput = { userId: userId, // 其他字段... };
内容的提问来源于stack exchange,提问作者Alistair Cooper
相关产品推荐
相关产品推荐

