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