消费管理
访问控制
访问控制只回答一个实际问题,这个用户现在能不能使用这个付费功能?
Pay4SaaS 提供两类工具:
- 通用访问判断,使用
useAccess()和checkUserAccess() - 订阅等级判断,使用
useTierAccess()和hasTierAccess()
不同定价模式的内部规则不同,但多数产品只需要按下面的方式接入。
定价模式
| 模式 | 通用访问含义 | 消费行为 |
|---|---|---|
| 积分模式 | 用户有可用积分 | 按 SERVICE_COSTS 扣积分 |
| 无限订阅 | 用户有有效订阅访问权 | 不扣积分 |
| 配额订阅 | 用户有订阅配额或可用积分 | 按 SERVICE_COSTS 扣配额或积分 |
| 买断制 | 用户有买断权益 | 不扣积分 |
前端判断
需要展示或隐藏付费 UI 时,使用 useAccess()。
import { useAccess } from '@/hooks/useAccess'
function PaidPanel() {
const { status, loading } = useAccess()
if (loading) return <div>加载中...</div>
if (!status.allowed) {
return <a href="/pricing">升级后继续</a>
}
return <div>你的付费功能</div>
}status.allowed 是通用的能不能访问结果。如果需要展示具体数值,按当前定价模式读取对应字段,例如 status.details.availableCredits、status.details.hasSubscription 或 status.details.hasLifetime。
前端判断只负责用户体验。真正的付费功能必须在服务端再次保护。
服务端判断
当 API route 只需要判断用户能不能访问某个付费功能时,使用 checkUserAccess()。
import { checkUserAccess } from '@/lib/payment/access'
import { getAuthUserId } from '@/lib/auth'
export async function POST() {
const userId = await getAuthUserId()
if (!userId) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
const access = await checkUserAccess(userId)
if (!access.allowed) {
return Response.json({ error: 'No access' }, { status: 403 })
}
return Response.json({ ok: true })
}消费一次付费服务
对于生成、分析、导出、API 调用这类按次使用的功能,前端调用 useService(),服务端调用 fastConsumeService()。这条路径会在一个流程里完成权限判断和用量记录。
import { useAccess } from '@/hooks/useAccess'
function GenerateButton() {
const { useService } = useAccess()
async function handleGenerate() {
const result = await useService('article_generation')
if (!result.success) {
alert(result.message)
return
}
// 权限确认后执行你的功能。
}
return <button onClick={handleGenerate}>生成</button>
}客户端只发送 serviceType。真实扣减数量来自 config/payment.ts 里的 SERVICE_COSTS,用户无法从浏览器篡改扣减金额。
// config/payment.ts
export const SERVICE_COSTS: Record<string, number> = {
'demo-consume': 25,
'article_generation': 10,
}服务端消费
import { fastConsumeService } from '@/lib/payment/access'
import { SERVICE_COSTS } from '@/config/payment'
const serviceType = 'article_generation'
const amount = SERVICE_COSTS[serviceType]
const result = await fastConsumeService(userId, amount, serviceType)
if (!result.success) {
return Response.json({ error: result.message }, { status: 403 })
}订阅等级门槛
当某个功能要求最低订阅等级时,使用 tier access,例如 Pro 才能导出、Max 才能使用高级分析。
import { useTierAccess } from '@/hooks/useTierAccess'
function ProFeatureButton() {
const canUsePro = useTierAccess('pro')
if (!canUsePro) {
return <a href="/pricing?plan=pro">升级到 Pro</a>
}
return <button>使用 Pro 功能</button>
}服务端等价写法:
import { hasTierAccess } from '@/lib/payment/access'
if (!await hasTierAccess(userId, 'pro')) {
return Response.json({ error: 'tier_required', required: 'pro' }, { status: 403 })
}通用访问用 status.allowed。需要判断最低订阅等级时,用 useTierAccess() 或 hasTierAccess()。
文档首页
回到完整实施目录。
价格方案
查看订阅、积分和终身买断方案。
博客
阅读更多 SaaS 支付和增长经验。