# VBase 权限系统文档 ## 1. 权限模型概述 VBase 是一个类似 **Supabase** 的 BaaS 平台,为 2C(个人开发者)和 2B(团队/企业)用户提供后端资源托管服务。权限系统采用 **RBAC + ABAC** 混合模型,支持三级权限体系: - **平台级 (Platform)**: 用户管理自己的账号和数据 - **项目级 (Project)**: 项目内的成员管理和资源控制 - **资源级 (Resource)**: 具体资源的读写操作 --- ## 2. 核心概念 ### 2.1 权限层级 ``` ┌─────────────────────────────────────────────────────────────┐ │ 平台级权限 (Platform) │ │ - 管理自己的用户信息 │ │ - 创建新项目 │ │ - 管理第三方账号绑定 │ │ - 访问被邀请的项目 │ └─────────────────────────────────────────────────────────────┘ │ ▼ (进入项目上下文) ┌─────────────────────────────────────────────────────────────┐ │ 项目级权限 (Project) │ │ - 项目设置管理 (所有者/管理员) │ │ - 成员邀请和管理 │ │ - 资源创建和管理 │ │ - 查看项目统计信息 │ └─────────────────────────────────────────────────────────────┘ │ ▼ (访问具体资源) ┌─────────────────────────────────────────────────────────────┐ │ 资源级权限 (Resource) │ │ - 数据库读写操作 │ │ - 存储文件上传下载 │ │ - 函数调用和管理 │ │ - API 密钥管理 │ └─────────────────────────────────────────────────────────────┘ ``` ### 2.2 实体关系 ``` User (平台用户) ├── Platform Permission (平台级权限) │ └── 默认: 管理自己的数据 │ └── OrgMember (项目成员关系) ├── Org/Project (项目) │ ├── Resource (项目资源) │ └── Resource (项目资源) │ └── Role (项目角色) └── Policy (策略) ``` ### 2.3 使用场景示例 **场景1: 个人开发者 (2C)** ``` 小明 (User) ├── 个人信息管理 (平台级) ├── 我的项目A (Org) │ ├── 数据库资源 │ └── 存储资源 └── 我的项目B (Org) └── ... ``` **场景2: 团队协作 (2B)** ``` CEO (User) ├── 拥有的项目: WebApp, MobileApp └── 角色: 所有者 (Owner) CTO (User) ├── 参与的项目: WebApp (Admin), MobileApp (Developer) └── 角色: 管理员/开发者 员工A (User) ├── 参与的项目: WebApp (Developer) └── 角色: 开发者 ``` ### 2.2 策略 (Policy) 策略是权限控制的最小单元,定义了对特定资源的操作权限。 **策略结构:** ```go type Policy struct { Code string // 策略编码,唯一标识 Name string // 策略名称 Description string // 策略描述 Resource string // 资源类型: user/org/member/policy/role/* Action string // 操作: create/read/update/delete/* Effect string // 效果: allow/deny Condition string // 条件表达式 Priority int // 优先级: 数字越大优先级越高 IsSystem bool // 是否系统策略 } ``` **策略分类:** **平台级策略** (无 org_id 上下文) | 策略 | 资源 | 操作 | 效果 | 条件 | 说明 | |------|------|------|------|------|------| | user:read:own | user | read | allow | owner | 读取自己的用户信息 | | user:update:own | user | update | allow | owner | 更新自己的用户信息 | | binding:manage | binding | * | allow | - | 管理第三方账号绑定 | | org:create | org | create | allow | - | 创建新项目 | **项目级策略** (需要 org_id 上下文) | 策略 | 资源 | 操作 | 效果 | 条件 | 说明 | |------|------|------|------|------|------| | org:admin | * | * | allow | org_owner | 项目所有者拥有所有权限 | | org:update | org | update | allow | admin | 更新项目设置 | | member:read | member | read | allow | member | 读取项目成员列表 | | member:manage | member | * | allow | admin | 管理项目成员 | | resource:create | resource | create | allow | developer | 创建项目资源 | | resource:delete | resource | delete | allow | admin | 删除项目资源 | ### 2.4 角色 (Role) 角色是一组策略的集合,在项目级别定义。 **角色结构:** ```go type Role struct { ID string // 角色ID OrgID string // 所属项目 Name string // 角色名称 Description string // 角色描述 PolicyIDs []string // 关联的策略ID列表 Scope string // 作用域: project/resource IsSystem bool // 是否系统角色 } ``` **系统内置角色:** | 角色 | 适用对象 | 权限范围 | 说明 | |------|----------|----------|------| | **owner** | 项目所有者 | 全部权限 | 项目的创建者,拥有所有权限,可删除项目 | | **admin** | 管理员 | 项目级管理 | 管理项目设置、成员、资源,但不能删除项目 | | **developer** | 开发者 | 资源级操作 | 创建和管理资源(数据库、存储、函数) | | **viewer** | 访客 | 只读访问 | 只能查看项目和资源信息,不能修改 | ### 2.4 条件 (Condition) 条件用于实现 ABAC,支持以下类型: | 条件 | 说明 | 使用场景 | |------|------|----------| | "" | 无条件,始终匹配 | 通用权限 | | "owner" | 资源所有者 | 只能操作自己的数据 | | "org_member" | 组织成员 | 组织内数据访问 | | "org_owner" | 组织所有者 | 所有者权限判断 | --- ## 3. 权限检查流程 ### 3.1 流程图 ``` ┌─────────────────┐ │ 请求进入 │ │ user, org, │ │ resource, action│ └────────┬────────┘ │ ▼ ┌─────────────────┐ 命中 ┌─────────────────┐ │ 检查缓存 │────────────→│ 返回缓存结果 │ │ Redis │ │ allow/deny │ └────────┬────────┘ └─────────────────┘ │ 未命中 ▼ ┌─────────────────┐ │ 1. 检查组织所有者 │────────┐ └────────┬────────┘ │ │ 是 │ ▼ │ ┌──────────┐ │ │ 返回 Allow│────────────┘ └──────────┘ │ 否 ▼ ┌─────────────────┐ │ 2. 获取用户角色 │ │ 从 OrgMember │ │ 获取 role_ids │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 3. 获取角色策略 │ │ 解析所有策略 │ │ 去重合并 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 4. 检查 Deny 策略│────────┐ │ 高优先级优先 │ │ └────────┬────────┘ │ │ 匹配 Deny │ ▼ │ ┌──────────┐ │ │返回 Deny │────────────┘ │ 缓存结果 │ └──────────┘ │ 无 Deny ▼ ┌─────────────────┐ │ 5. 检查 Allow 策略│────────┐ └────────┬────────┘ │ │ 匹配 Allow │ ▼ │ ┌──────────┐ │ │返回 Allow│────────────┘ │ 缓存结果 │ └──────────┘ │ 无 Allow ▼ ┌─────────────────┐ │ 6. 默认拒绝 │────────→ 返回 Deny └─────────────────┘ 缓存结果 ``` ### 3.2 决策规则 1. **Deny 优先**: 如果匹配到 Deny 策略,直接拒绝 2. **显式 Allow**: 必须匹配到 Allow 策略才允许 3. **默认拒绝**: 未匹配到任何策略时拒绝 4. **优先级**: 高优先级策略优先匹配 --- ## 4. 使用指南 ### 4.1 检查权限 **代码示例:** ```go import "github.com/veypi/vbase/internal/service" func SomeHandler(x *vigo.X) error { userID := middleware.CurrentUser(x) orgID := middleware.CurrentOrg(x) checker := service.NewPermissionChecker() result, err := checker.Check(userID, orgID, "user", "update", map[string]any{ "owner_id": targetUserID, }) if err != nil || !result.Allowed { return vigo.ErrForbidden.WithString(result.Reason) } // 继续处理... } ``` ### 4.2 创建自定义策略 ```go policy := &model.Policy{ Code: "custom:resource:action", Name: "自定义策略", Description: "允许特定用户操作", Resource: "resource_name", Action: "action_name", // create/read/update/delete Effect: model.EffectAllow, Condition: "owner", // owner/org_member/空 Priority: 50, } model.DB.Create(policy) ``` ### 4.3 创建角色并授权 ```go // 创建角色 role := &model.Role{ OrgID: orgID, Name: "部门管理员", Description: "管理部门成员", PolicyIDs: "policy1,policy2,policy3", } model.DB.Create(role) // 分配给用户 member := &model.OrgMember{ OrgID: orgID, UserID: userID, RoleIDs: role.ID, } model.DB.Create(member) ``` --- ## 5. 系统内置策略 ### 5.1 用户相关 ```go // 读取自己 SysPolicyUserReadOwn = "sys:user:read:own" Resource: "user" Action: "read" Condition: "owner" // 更新自己 SysPolicyUserUpdateOwn = "sys:user:update:own" Resource: "user" Action: "update" Condition: "owner" // 删除自己 SysPolicyUserDeleteOwn = "sys:user:delete:own" Resource: "user" Action: "delete" Condition: "owner" ``` ### 5.2 组织相关 ```go // 组织管理员 SysPolicyOrgAdmin = "sys:org:admin" Resource: "*" Action: "*" Condition: "org_owner" Priority: 100 // 读取组织 SysPolicyOrgRead = "sys:org:read" Resource: "org" Action: "read" Condition: "org_member" ``` ### 5.3 成员相关 ```go // 读取成员 SysPolicyMemberRead = "sys:member:read" Resource: "member" Action: "read" Condition: "org_member" // 管理成员 SysPolicyMemberManage = "sys:member:manage" Resource: "member" Action: "*" Condition: "" ``` ### 5.4 角色策略相关 ```go // 读取角色 SysPolicyRoleRead = "sys:role:read" Resource: "role" Action: "read" Condition: "org_member" // 管理角色 SysPolicyRoleManage = "sys:role:manage" Resource: "role" Action: "*" Condition: "" // 读取策略 SysPolicyPolicyRead = "sys:policy:read" Resource: "policy" Action: "read" Condition: "" // 管理策略 SysPolicyPolicyManage = "sys:policy:manage" Resource: "policy" Action: "*" Condition: "" ``` --- ## 6. 权限缓存 ### 6.1 缓存机制 ``` 缓存键: perm:{user_id}:{org_id}:{resource}:{action} TTL: 1分钟 值: "allow" 或 "deny" ``` ### 6.2 缓存失效 以下操作会触发缓存清除: - 用户角色变更 - 角色策略变更 - 策略内容变更 - 组织成员变更 ```go // 清除用户权限缓存 service.ClearUserPermissionCache(userID) // 清除组织权限缓存 service.ClearOrgPermissionCache(orgID) ``` ### 6.3 缓存命中率优化 - 权限变更频率低,1分钟 TTL 平衡了性能和实时性 - 批量操作时建议先清除缓存,操作完成后统一刷新 --- ## 7. 最佳实践 ### 7.1 策略设计 1. **最小权限原则**: 只授予完成任务所需的最小权限 2. **职责分离**: 敏感操作需要多个角色共同完成 3. **策略命名规范**: `{resource}:{action}:{condition}` ### 7.2 角色设计 ``` 组织层级角色体系: ├── owner (所有者) │ └── 全部权限 ├── admin (管理员) │ └── 管理成员、角色、策略 ├── manager (部门经理) │ └── 管理部门成员 └── member (普通成员) └── 基础访问权限 ``` ### 7.3 权限检查位置 **Controller 层检查:** ```go func Handler(x *vigo.X) error { // 先检查权限 if !hasPermission(x, "resource", "action") { return vigo.ErrForbidden } // 执行业务逻辑 } ``` **Service 层检查(数据级):** ```go func UpdateUser(userID string, data map[string]any) error { // 检查是否是本人或管理员 if !isOwner(userID) && !hasAdminRole() { return ErrForbidden } // 执行更新 } ``` ### 7.4 权限测试 ```go func TestPermissionCheck(t *testing.T) { tests := []struct { name string userID string orgID string resource string action string data map[string]any want bool }{ { name: "owner can update own profile", userID: "user1", orgID: "", resource: "user", action: "update", data: map[string]any{"owner_id": "user1"}, want: true, }, { name: "user cannot update others profile", userID: "user1", orgID: "", resource: "user", action: "update", data: map[string]any{"owner_id": "user2"}, want: false, }, } checker := service.NewPermissionChecker() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, _ := checker.Check(tt.userID, tt.orgID, tt.resource, tt.action, tt.data) if result.Allowed != tt.want { t.Errorf("Check() = %v, want %v", result.Allowed, tt.want) } }) } } ``` --- ## 8. 故障排查 ### 8.1 权限检查失败 **检查步骤:** 1. 确认用户已登录 2. 确认用户是组织成员 3. 检查用户角色 4. 检查角色绑定的策略 5. 检查策略的 Effect 和 Condition **调试日志:** ```go // 开启调试日志 checker := service.NewPermissionChecker() result, err := checker.Check(userID, orgID, resource, action, data) log.Printf("Permission check: user=%s, resource=%s, action=%s, allowed=%v, reason=%s", userID, resource, action, result.Allowed, result.Reason) ``` ### 8.2 缓存问题 ```bash # 清除 Redis 权限缓存 redis-cli KEYS "perm:*" | xargs redis-cli DEL # 或重启应用(开发环境) ``` ### 8.3 权限不生效 1. 检查策略是否保存成功 2. 检查角色是否正确绑定策略 3. 检查用户是否正确分配角色 4. 检查缓存是否已清除 --- ## 9. 扩展开发 ### 9.1 添加自定义条件 ```go // 在 permission.go 中扩展 evaluateCondition func (pc *PermissionChecker) evaluateCondition(p *model.Policy, userID, orgID string, resourceData map[string]any) bool { switch p.Condition { case "owner": // 现有逻辑... case "custom_condition": // 自定义条件逻辑 return checkCustomCondition(userID, orgID, resourceData) default: return true } } ``` ### 9.2 添加资源类型 ```go // 在 policy.go 中添加资源常量 const ( ResourceUser = "user" ResourceOrg = "org" ResourceMember = "member" ResourceCustom = "custom_resource" // 新增 ) ``` --- ## 10. 参考 - [RBAC 模型](https://en.wikipedia.org/wiki/Role-based_access_control) - [ABAC 模型](https://en.wikipedia.org/wiki/Attribute-based_access_control) - [NIST RBAC 标准](https://csrc.nist.gov/projects/role-based-access-control)