用途
该技能用于在应用中实现安全的订阅支付,采用 Clerk Billing 与 Stripe 组合,使应用自身永不接触信用卡数据。资料明确指出:如果存储、处理或传输信用卡数据,就必须遵守 PCI-DSS,包括年度安全审计、季度漏洞扫描、加密持卡人数据等,小型公司 84% 未通过初次 PCI 审计,持续合规成本每年 5 万至 20 万美元。因此该技能主张通过架构设计把合规责任交给 Stripe,应用不承担 PCI-DSS 义务。
主要能力
- 使用 Clerk 的 PricingTable 组件展示订阅计划(Free、Basic、Pro)。
- 通过 Clerk 打开 Stripe Checkout 完成支付,卡号、CVV、有效期等只在 Stripe 服务器输入与处理。
- 应用只存储订阅状态、订阅开始日期、Stripe 客户 ID 等非敏感信息。
- 提供 Clerk Webhook 与 Convex Webhook 两种接收订阅事件的方式,事件包括 subscription.created、subscription.updated、subscription.deleted、user.created、user.updated、subscription.payment_failed。
- 提供服务端与客户端两种订阅状态检查方式:服务端通过 auth() 读取 sessionClaims 中的 plan;客户端通过 Protect 组件按 plan 条件渲染。
- 提供失败支付处理流程与示例代码。
- 提供 Stripe 测试卡与 Stripe CLI 转发 Webhook 的测试方法。
使用方式
- 在 Clerk Dashboard 的 Billing 中连接 Stripe 账户,创建订阅计划,复制 Clerk Billing publishable key。
- 配置环境变量:NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY、CLERK_SECRET_KEY、CLERK_WEBHOOK_SECRET。资料说明 Stripe 由 Clerk Billing 自动配置,无需手动 Stripe 密钥。
- 添加 PricingTable 组件(components/custom-clerk-pricing.tsx)。
- 在服务端 API 路由中通过 auth() 检查 plan,拒绝 free_user 访问付费功能。
- 在客户端组件中使用 Protect 组件,condition 为 !has({ plan: "free_user" }),fallback 展示升级提示。
- 实现 Webhook 接收端点,使用 Svix 的 Webhook 类验证签名,再按事件类型更新数据库中的订阅与用户 plan。
- 使用 Stripe 测试卡(成功 4242 4242 4242 4242、拒付 4000 0000 0000 0002、3D Secure 4000 0025 0000 3155、余额不足 4000 0000 0000 9995)在开发环境测试。
- 使用 stripe listen --forward-to localhost:3000/api/webhooks/clerk 转发 Webhook,并用 stripe trigger subscription.created 触发测试事件。
适用场景
- 需要为应用添加订阅制付费访问控制的场景。
- 希望避免自行处理信用卡数据、规避 PCI-DSS 合规负担的团队。
- 使用 Clerk 做身份认证、使用 Stripe 做支付的 Next.js 应用。
- 使用 Convex 作为后端并需要接收 Clerk Webhook 的项目。
限制与注意事项
- 资料未提供该技能的具体安装命令或包名,仅给出实现文件路径与代码示例。
- 资料未说明该技能的收费、价格或平台限制。
- 资料强调必须验证 Webhook 签名,不能信任未验证的 Webhook 数据。
- 不能存储卡号、CVV、有效期等支付信息,只能存储 Stripe 内部 ID。
- 访问控制必须在服务端校验,不能仅依赖客户端检查。
- 需要实现幂等性以处理重复 Webhook。
- 不能忘记处理失败支付,不能在客户端代码中暴露 Stripe 密钥。
- 资料中引用的外部文档链接包括 Clerk Billing、Stripe Checkout、PCI-DSS、Stripe Testing、Svix Webhook Security。