feat(rbac): 租户角色门控落地(极简版) —— viewer/billing_admin 只读不可提交任务
角色此前能分配但不生效(viewer 也能烧租户积分)。本次让角色真正挡动作: - store.RoleRank 角色层级:owner(4)>admin(3)>member(2)>viewer/billing_admin(1), 未知/非成员=0;billing_admin 定位为「财务只读」不跑任务 - 可复用中间件 RequireTenantRole(db, minRole),抽 MemberRoleResolver 小接口便于单测 - POST /tasks 挂 ≥member 门控:唯一会烧租户积分的入口(KB 入库不计租户),挡住即够 - 桌面端 StudioView 收 readOnly:viewer 时「运行」禁用+只读提示(UX 兜底,真闸在后端) - 测试:RoleRank 纯逻辑 + 中间件 7 门控 case(owner/admin/member 放行, viewer/billing_admin/非成员 403,未登录 401) 实机验证(gateway+docker):viewer 提交 403 → 升 member 202 → 降回 viewer 403 → owner 自租户 202(solo 用户不受影响),三态可逆、角色驱动、中间件先于 handler。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,24 @@ const (
|
||||
RoleBillingAdmin = "billing_admin"
|
||||
)
|
||||
|
||||
// RoleRank 返回角色在「操作/管理」阶梯上的等级(越大权越高),供 RequireTenantRole 门控。
|
||||
// 语义:viewer 与 billing_admin 均为只读(1)——billing_admin 是「财务只读」角色,管账不跑任务,
|
||||
// 故不能提交(烧租户积分);member 可操作(2);admin(3)/owner(4) 递增管理权。
|
||||
// 未知角色 / 非成员(空串)记 0,一律拦下。当前唯一接入点:SubmitTask 要求 ≥ member(挡 viewer/billing_admin 烧租户积分)。
|
||||
func RoleRank(role string) int {
|
||||
switch role {
|
||||
case RoleOwner:
|
||||
return 4
|
||||
case RoleAdmin:
|
||||
return 3
|
||||
case RoleMember:
|
||||
return 2
|
||||
case RoleViewer, RoleBillingAdmin:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// CreateTenant 建一个租户。
|
||||
func (p *Postgres) CreateTenant(ctx context.Context, name, slug, plan string) (*Tenant, error) {
|
||||
if p.db == nil {
|
||||
|
||||
Reference in New Issue
Block a user