|
|
# 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)
|