如何设计额度和权限表
额度和权限是 AI 产品商业化和安全运营的两大基础。额度控制用户「能用多少」,权限决定用户「能做什么」。二者共同构成产品的商业化边界与安全屏障——额度表错了,用户可能无限消耗 API 调用导致成本失控;权限表错了,普通用户可能访问到管理员功能,造成数据泄露。
本文从数据库表结构层面,系统拆解额度表设计、权限表设计、RBAC 模型,以及二者之间的关联方式,帮助你在 AI 产品出海的过程中建立可靠的用量控制与访问控制体系。
一、额度表设计
1.1 为什么需要独立的额度表
在 AI 产品中,每一次生成、每一次对话、每一次图像渲染都有真实的计算成本。如果不做额度管理,产品只能依赖简单的请求频率限制(Rate Limit),无法实现按量计费、分层套餐、免费试用等商业化策略。
额度表的核心职责是回答三个问题:
- 这个用户还有多少可用额度?
- 额度从哪里来、怎么刷新?
- 额度用尽时如何处理?
1.2 额度表字段设计
一个典型的额度表 user_quotas 需要包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id | UUID / BIGSERIAL | 主键 |
user_id | UUID | 关联用户表 |
quota_type | VARCHAR(50) | 额度类型,如 image_generation、text_completion、api_call |
total_amount | BIGINT | 当前周期内总额度 |
used_amount | BIGINT | 已使用额度 |
remaining_amount | BIGINT | 剩余额度(可用计算列或缓存字段) |
period_start | TIMESTAMPTZ | 当前周期开始时间 |
period_end | TIMESTAMPTZ | 当前周期结束时间 |
refresh_policy | VARCHAR(20) | 刷新策略:daily、monthly、yearly、one_time |
status | VARCHAR(20) | 状态:active、exhausted、suspended |
created_at | TIMESTAMPTZ | 创建时间 |
updated_at | TIMESTAMPTZ | 更新时间 |
几个设计要点:
remaining_amount是否冗余:可以设为计算列(total_amount - used_amount),但在高并发场景下,冗余存储并配合数据库事务能保证原子性,避免重复计算带来的性能开销。quota_type用字符串而非枚举:AI 产品的额度类型会频繁增加(新的模型、新的功能),字符串更容易扩展。如果追求强类型约束,可以使用数据库枚举并配合 migration 更新。- 周期字段:
period_start和period_end让额度过期和刷新逻辑变得明确,避免依赖模糊的「上次刷新时间」推断。
1.3 额度类型与来源
AI 产品的额度通常分为两类:
| 额度类型 | 说明 | 典型场景 |
|---|---|---|
| 免费额度(Free Quota) | 注册即赠,用于产品试用 | 新用户赠送 50 次图片生成 |
| 付费额度(Paid Quota / Credits) | 用户购买获得,按量消耗 | 购买 1000 Credits 用于 API 调用 |
在表结构上,有两种处理方式:
方案 A:单表多行——同一个 user_quotas 表,通过 quota_type 区分免费和付费额度。每行代表一种额度来源。优点是查询简单,缺点是无法表达优先级。
方案 B:增加 source 字段——在表中增加 source 字段(free、purchased、gifted),并增加 priority 字段决定扣减顺序。扣减时按优先级从高到低消耗,优先使用免费额度。
推荐方案 B,因为它更贴近真实的业务逻辑:大多数产品都会优先消耗免费额度,再用付费额度。
1.4 额度刷新策略
额度刷新是设计中容易忽视的环节。不同产品有不同的刷新节奏:
| 刷新策略 | 适用场景 | 实现方式 |
|---|---|---|
| 每日刷新(Daily) | 高频 API 调用限制 | 定时任务每日 00:00 重置 used_amount |
| 每月刷新(Monthly) | SaaS 订阅套餐 | 在订阅周期开始时重置额度 |
| 一次性(One-time) | 购买的 Credits 包 | 不刷新,用完即止 |
| 按周期滚动(Rolling) | 企业级合同 | 未使用额度按比例结转至下一周期 |
实现刷新的关键是幂等性:刷新操作必须确保同一周期内不会重复执行。常见做法是在 user_quotas 表上记录 last_refreshed_period(如 2026-07),刷新前先检查该字段,如果已经等于当前周期则跳过。
1.5 额度扣减与超限处理
额度扣减必须在事务中完成,核心流程是:
- 查询用户当前可用额度(
SELECT ... FOR UPDATE行级锁)。 - 判断剩余额度是否足够本次消费。
- 如果足够,
UPDATE used_amount = used_amount + cost并返回成功。 - 如果不足,根据产品策略执行超限处理。
超限处理策略包括:
- 硬限制:直接拒绝请求,返回
402 Payment Required或429 Too Many Requests。 - 软限制 + 通知:允许一定程度的超额使用,同时发送邮件或站内通知提醒用户充值。
- 自动升级:当免费额度耗尽时,自动触发付费流程或升级到更高套餐。
对于出海产品,硬限制是更安全的选择。AI 模型的调用成本是实时的,超额使用意味着直接的美元支出,不允许「先欠后还」。
二、权限表设计
2.1 权限模型的选择
权限控制有三种常见模型:
| 模型 | 说明 | 适用场景 |
|---|---|---|
| ACL(Access Control List) | 直接给用户分配权限 | 小型系统、权限简单 |
| RBAC(Role-Based Access Control) | 用户 → 角色 → 权限 | 中大型系统、多角色多权限 |
| ABAC(Attribute-Based Access Control) | 基于属性的策略引擎 | 超大型系统、复杂策略 |
对于 AI 产品出海,RBAC 是最平衡的选择。它比 ACL 更灵活,比 ABAC 更简单,能够满足绝大多数 SaaS 产品的权限需求。
2.2 RBAC 核心表结构
RBAC 的经典设计需要五张表:
用户表 users(已存在,此处只列出关键字段):
| 字段 | 类型 | 说明 |
|---|---|---|
id | UUID | 主键 |
email | VARCHAR(255) | 用户邮箱 |
status | VARCHAR(20) | 账户状态 |
角色表 roles:
| 字段 | 类型 | 说明 |
|---|---|---|
id | UUID / SERIAL | 主键 |
name | VARCHAR(50) | 角色名称,如 admin、editor、viewer |
display_name | VARCHAR(100) | 显示名称 |
description | TEXT | 角色说明 |
is_system | BOOLEAN | 是否系统内置角色(不可删除) |
created_at | TIMESTAMPTZ | 创建时间 |
权限表 permissions:
| 字段 | 类型 | 说明 |
|---|---|---|
id | UUID / SERIAL | 主键 |
code | VARCHAR(100) | 权限编码,如 image:generate、project:delete |
resource | VARCHAR(50) | 资源类型,如 image、project、settings |
action | VARCHAR(50) | 操作类型,如 create、read、update、delete |
description | TEXT | 权限说明 |
created_at | TIMESTAMPTZ | 创建时间 |
用户-角色关联表 user_roles:
| 字段 | 类型 | 说明 |
|---|---|---|
id | BIGSERIAL | 主键 |
user_id | UUID | 关联用户 |
role_id | UUID / INTEGER | 关联角色 |
granted_at | TIMESTAMPTZ | 授予时间 |
expires_at | TIMESTAMPTZ | 过期时间(可选,用于临时角色) |
角色-权限关联表 role_permissions:
| 字段 | 类型 | 说明 |
|---|---|---|
id | BIGSERIAL | 主键 |
role_id | UUID / INTEGER | 关联角色 |
permission_id | UUID / INTEGER | 关联权限 |
granted_at | TIMESTAMPTZ | 授予时间 |
2.3 权限编码规范
权限编码(code)是代码中实际使用的标识符,设计规范直接影响代码的可读性和可维护性。
推荐采用 resource:action 的二级格式:
image:generate -- 生成图片
image:delete -- 删除图片
project:create -- 创建项目
project:share -- 分享项目
team:manage -- 管理团队成员
billing:update -- 更新账单信息
admin:system_config -- 系统配置
如果业务更复杂,可以扩展到三级 resource:action:scope,例如 project:read:own(只读自己的项目)和 project:read:all(读取所有项目)。但三级格式会增加复杂度,建议只在确实需要数据范围区分时才引入。
2.4 功能访问控制的实现
在应用层,权限校验通常以中间件或装饰器的形式实现:
// 中间件伪代码
function requirePermission(permissionCode: string) {
return async (req, res, next) => {
const user = req.auth.user;
const permissions = await getUserPermissions(user.id);
if (!permissions.includes(permissionCode)) {
return res.status(403).json({ error: 'Permission denied' });
}
next();
};
}
// 使用
router.post('/api/images/generate', requirePermission('image:generate'), generateHandler);
router.delete('/api/projects/:id', requirePermission('project:delete'), deleteHandler);性能优化方面,用户权限在登录后缓存到 Redis 或 JWT 的 claims 中,避免每次请求都查询数据库。权限变更时清除对应缓存即可。
三、RBAC 模型的扩展
3.1 角色层级
在实际产品中,角色往往有层级关系。例如 admin 角色自动继承 editor 和 viewer 的所有权限。实现方式有两种:
方案 A:显式继承——在 roles 表中增加 parent_role_id 字段,形成树形结构。查询权限时递归向上收集所有祖先角色的权限。
方案 B:权限聚合——不设层级,在分配角色时直接将所有需要的权限显式关联。管理上稍显冗余,但查询更简单,性能更好。
对于中小规模的 AI 产品,推荐方案 B。角色数量通常不超过 10 个,显式分配带来的冗余完全可以接受,而且避免了递归查询的复杂度。
3.2 多租户与团队权限
出海 SaaS 产品通常需要支持多团队(Workspace / Organization)。此时 RBAC 表需要增加租户维度:
- 在
user_roles表中增加workspace_id字段,表示用户在某个工作空间中的角色。 - 同一个用户在不同工作空间可以有不同的角色和权限。
roles表可以是全局的(所有工作空间共享同一套角色定义),也可以是工作空间级别的(每个工作空间可以自定义角色)。
推荐先做全局角色,后续根据客户需求再开放自定义角色的能力。过早引入工作空间级别的自定义角色会显著增加系统复杂度。
3.3 数据权限
RBAC 控制的是功能权限(能不能做某个操作),但有时候还需要控制数据权限(能看到哪些数据)。例如:普通编辑者只能看到自己创建的项目,管理员可以看到所有项目。
数据权限通常在业务查询层实现,而非在权限表中定义。常见做法是在 permissions 表中增加 scope 字段:
| scope 值 | 含义 |
|---|---|
own | 只能访问自己创建的数据 |
team | 可以访问团队成员的数据 |
all | 可以访问所有数据 |
在查询时,根据 scope 动态拼接 WHERE 条件。这种方式简单有效,但要注意 scope 的判断逻辑应该封装在统一的数据访问层,避免散落在各个业务模块中。
四、额度和权限的关联
额度和权限不是孤立的,它们在产品中经常协同工作。典型场景:
- 权限决定能不能用,额度决定能用多少:用户必须有
image:generate权限,并且额度充足,才能发起图片生成请求。 - 套餐同时绑定角色和额度:
Pro套餐的用户自动获得editor角色和每月 5000 次生成额度。 - 管理员权限可以调整他人额度:拥有
team:manage权限的管理员可以给团队成员分配额外额度。
在数据库层面,关联方式有两种:
松耦合:额度表和权限表各自独立,在业务逻辑层做联合判断。请求进来时,先检查权限,再检查额度,两步都通过才放行。
紧耦合:在套餐表(plans)中同时定义角色和额度,用户订阅套餐时自动创建对应的角色关联和额度记录。
推荐松耦合方案。额度和权限的职责不同,变更频率也不同(权限相对稳定,额度随套餐变化),保持独立更利于维护和演进。
五、额度和权限的校验流程
以下流程图展示了用户发起请求时,系统如何联合校验额度和权限:
关键设计点:
- 权限校验在额度校验之前:先确认用户有没有资格做这件事,再检查额度是否充足。如果反过来,没有权限的用户也能探测到额度信息,造成信息泄露。
- 额度扣减在执行之后:如果请求执行失败(如模型调用超时),不应该扣减额度。确保扣减操作在确认成功后执行,或者采用「预扣减 + 确认/回滚」的两阶段模式。
- 阈值预警:当额度使用达到 80% 或 90% 时主动通知用户,避免用户在不知情的情况下突然被中断服务。
六、实战案例
案例 1:AI 图片生成平台的额度设计
某 AI 图片生成平台提供三种套餐:
| 套餐 | 月费 | 每月额度 | 刷新策略 | 附加权限 |
|---|---|---|---|---|
| Free | $0 | 50 次生成 | 每月刷新 | 仅标准画质 |
| Pro | $19 | 2000 次生成 | 每月刷新 | 高清画质 + API 访问 |
| Enterprise | $99 | 10000 次生成 | 每月刷新 | 全部功能 + 团队管理 |
在数据库层面,用户订阅套餐时:
- 在
user_roles中插入对应角色关联(如pro_user)。 - 在
user_quotas中创建或更新额度记录,设置total_amount = 2000,refresh_policy = 'monthly'。 - 每月订阅续费时,刷新额度:重置
used_amount = 0,更新period_start和period_end。
案例 2:多团队协作的权限设计
某 AI 写作工具的团队权限结构如下:
| 角色 | 权限 |
|---|---|
owner | 所有权限,包括删除团队、管理账单 |
admin | 管理成员、管理项目、查看所有数据 |
editor | 创建和编辑自己的项目、分享项目 |
viewer | 只读访问被分享的项目 |
实现时,roles 表中预置四个角色,role_permissions 表中预置每个角色对应的权限集合。用户被邀请加入团队时,默认分配 viewer 角色,管理员可以在团队设置中修改成员角色。
这种设计的好处是:权限变更不需要修改代码,只需要在后台调整 role_permissions 的关联关系。新增功能时,只需要在 permissions 表中插入新权限,并将其关联到合适的角色。
七、设计检查清单
在落地额度和权限表设计时,逐项检查以下要点:
- 额度表是否区分了额度类型和来源?——免费额度和付费额度应该可以独立追踪。
- 额度刷新是否具备幂等性?——同一周期内不会重复刷新。
- 额度扣减是否在事务中执行?——避免并发导致的超卖问题。
- 超额处理策略是否明确?——硬限制还是软限制,是否有自动升级机制。
- 权限编码是否遵循统一规范?——
resource:action格式,易于理解和扩展。 - RBAC 表是否支持多租户?——同一个用户在不同团队中可以有不同的角色。
- 权限校验是否在额度校验之前?——先验权再验额度,避免信息泄露。
- 权限变更是否及时生效?——缓存刷新机制是否到位。
- 系统内置角色是否受到保护?——
is_system标记的内置角色不允许删除或修改编码。 - 额度预警通知是否配置?——阈值预警是否覆盖 80% 和 90% 的使用节点。
- 是否有额度使用日志?——每次扣减都应该有可追溯的流水记录。
- 数据库索引是否合理?——
user_id、quota_type、role_id、permission_id等高频查询字段是否建立了索引。
八、小结
额度表和权限表是 AI 产品后端基础设施的重要组成部分。额度表解决「用多少」的问题,需要关注额度类型、刷新策略、扣减事务和超限处理;权限表解决「能不能用」的问题,需要关注 RBAC 模型、权限编码规范和多层级扩展。
二者在请求校验流程中协同工作:先验权限,再验额度,通过后执行请求并扣减额度。设计上保持松耦合,通过业务逻辑层进行联合判断,可以让系统更灵活地应对产品迭代。
出海场景下,还需要额外关注多租户隔离、货币单位(Credits vs. 次数 vs. Token 数)和合规要求(GDPR 下的数据访问权限)。这些内容会在后续的国际化与合规章节中展开。
参考资料
- Designing a Simple Quota System — LaikaTest 关于可扩展额度系统的设计实践
- RBAC user permission database design — 阿里云开发者社区的 RBAC 数据库设计方案
- How to Design an RBAC System — NocoBase 的 RBAC 系统设计指南
- Best RBAC database model — Stack Overflow 上关于 RBAC 数据库模型的经典讨论
- Scalable API Rate Limiting & Quota Management System — 可扩展 API 限流与额度管理系统设计
- 经典角色权限系统设计五张表及拓展应用 — 牛客网的 RBAC 五张表设计与拓展讨论
- 多租户 SaaS 应用中 RBAC 可扩展设计 — 火山引擎关于多租户 SaaS 权限设计的方案
- Database design for credit-based purchases — Stack Overflow 关于 Credits 购买系统的数据库设计讨论