update doc

v3
veypi 1 week ago
parent 2303b031d2
commit 809bba7417

@ -7,9 +7,40 @@
| 文档 | 说明 | | 文档 | 说明 |
|------|------| |------|------|
| [API 文档](./api.md) | 完整的 API 接口文档,包含请求/响应格式 | | [API 文档](./api.md) | 完整的 API 接口文档,包含请求/响应格式 |
| [架构设计](./architecture.md) | 系统架构、模块设计、数据模型 | | [架构设计](./architecture.md) | 系统架构、模块设计、数据模型、BaaS 资源管理 |
| [部署指南](./deployment.md) | 环境配置、Docker 部署、运维指南 | | [部署指南](./deployment.md) | 环境配置、Docker 部署、运维指南 |
| [权限系统](./permission.md) | RBAC+ABAC 权限模型使用指南 | | [权限系统](./permission.md) | RBAC+ABAC 权限模型、三级权限体系使用指南 |
## 项目定位:可私有化部署的 IAM + BaaS 产品
VBase 是一个 **产品化的 IAM + BaaS 平台**,你可以将其**售卖/部署**给终端客户:
### 三层级架构
| 层级 | 角色 | 说明 |
|------|------|------|
| **平台层** | 平台运营商(你) | 管理 VBase 产品,提供部署和运维服务 |
| **实例层** | 客户2C/2B/混合) | 独立部署 VBase 实例,完全隔离 |
| **业务层** | 终端用户 | 使用客户的产品,与你无直接关系 |
### 两种交付模式
1. **托管部署**:你在自己的云基础设施上为客户部署 VBase 实例,负责运维
2. **客户自托管**:客户在自己的环境中部署,数据完全自主可控
### 客户类型
- **2C 产品公司**(社交 App、电商平台用 VBase 管理用户注册、登录、个人数据
- **2B 产品公司**SaaS、企业软件用 VBase 做多租户隔离、组织架构、权限管理
- **混合产品公司**电商平台、O2O同时管理 C 端用户和 B 端企业
## 核心特性
- **项目-资源隔离**: 多项目数据隔离,支持个人/团队场景
- **三级权限体系**: 平台级 → 项目级 → 资源级
- **RBAC + ABAC**: 角色与策略结合的细粒度权限控制
- **Redis 缓存**: 权限缓存 1 分钟 TTL平衡性能与实时性
- **资源级权限**: 数据库、存储、函数、API 密钥的细粒度控制
## 快速开始 ## 快速开始

@ -4,13 +4,47 @@
VBase 是一个类似 **Supabase****Backend-as-a-Service (BaaS)** 平台为个人开发者2C和团队/企业2B提供后端资源托管和权限管理服务。采用 Go 语言开发,基于 Vigo 框架构建。 VBase 是一个类似 **Supabase****Backend-as-a-Service (BaaS)** 平台为个人开发者2C和团队/企业2B提供后端资源托管和权限管理服务。采用 Go 语言开发,基于 Vigo 框架构建。
### 1.1 产品定位 ### 1.1 产品定位:可私有化部署的 IAM + BaaS 平台
| 用户类型 | 使用场景 | 功能需求 | VBase 是一个**产品化**的解决方案,你可以将 VBase **售卖/部署**给终端客户,客户在自己的环境中独立运行 VBase 实例,完全隔离地管理自己的业务。
|----------|----------|----------|
| **个人开发者 (2C)** | 创建个人项目,管理应用后端资源 | 项目管理、资源隔离、API 访问 | #### 三层级架构模型
| **团队/初创 (2B)** | 团队协作开发,共享项目资源 | 成员管理、角色权限、组织隔离 |
| **企业客户 (2B)** | 多项目/多团队管理,合规要求 | 组织架构、细粒度权限、审计日志 | ```
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: VBase 平台运营层 (你的 SaaS 平台) │
│ - 你是 VBase 产品的提供商 │
│ - 功能:实例管理、计费、监控、版本分发 │
│ - 部署模式:托管部署 or 客户自托管 │
└─────────────────────────────────────────────────────────────┘
▼ 部署/交付
┌─────────────────────────────────────────────────────────────┐
│ Layer 2: VBase 实例层 (客户的独立部署) │
│ - 每个客户拥有一个完全独立的 VBase 实例 │
│ - 独立数据库、独立用户体系、独立配置 │
│ - 客户可以是2C 产品 / 2B 产品 / 混合产品 │
│ - 管理员:客户的技术负责人/运维 │
└─────────────────────────────────────────────────────────────┘
▼ 使用
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: 客户业务层 (与你无关) │
│ - 客户用 VBase 管理自己的终端用户和业务项目 │
│ ├─ 2C 场景App 用户注册登录、个人数据管理 │
│ ├─ 2B 场景:企业内部系统、团队协作 │
│ └─ 混合场景:既有终端用户又有内部团队 │
│ - 用户数据完全属于客户,与你无关 │
└─────────────────────────────────────────────────────────────┘
```
#### 目标客户类型
| 客户类型 | 场景说明 | VBase 提供的价值 |
|----------|----------|-----------------|
| **2C 产品公司** | 社交 App、电商平台、内容社区等 | 用户认证、个人数据管理、权限控制 |
| **2B 产品公司** | SaaS 软件、企业管理系统 | 多租户隔离、组织架构、RBAC 权限 |
| **混合产品公司** | 既有 C 端用户又有 B 端管理 | 统一身份管理、分级权限控制 |
### 1.2 核心特性 ### 1.2 核心特性
@ -35,16 +69,28 @@ VBase 是一个类似 **Supabase** 的 **Backend-as-a-Service (BaaS)** 平台,
### 1.4 概念说明 ### 1.4 概念说明
**项目 (Project/Org)**: 资源管理的基本单元 #### 三层级角色体系
- 个人开发者创建的项目 = 个人项目
- 团队创建的项目 = 团队项目 | 层级 | 角色 | 说明 | 权限范围 |
- 企业可以创建多个项目,也可以使用组织层级管理 |------|------|------|----------|
| **平台层** | 平台管理员 | VBase 产品提供商(你) | 管理所有 VBase 实例 |
| **实例层** | 实例管理员 | 客户的技术负责人 | 管理自己的 VBase 实例配置 |
| **业务层** | 终端用户 | 客户的 C 端用户或 B 端成员 | 使用客户的产品功能 |
**用户 (User)**: 平台注册用户 #### VBase 实例内部概念
在一个独立的 VBase 实例内部,包含以下核心概念:
**用户 (User)**: VBase 实例中的注册用户
- 可以创建多个项目 - 可以创建多个项目
- 可以被邀请加入其他项目 - 可以被邀请加入其他项目
- 在不同项目中可以有不同的角色 - 在不同项目中可以有不同的角色
**项目/组织 (Project/Org)**: 资源管理的基本单元
- 对 2C 场景:对应一个 App 或产品
- 对 2B 场景:对应一个企业或部门
- 企业可以创建多个项目,也可以使用组织层级管理
**资源 (Resource)**: 项目内的后端资源 **资源 (Resource)**: 项目内的后端资源
- 数据库、存储、函数、API 等 - 数据库、存储、函数、API 等
- 属于特定项目 - 属于特定项目
@ -115,7 +161,99 @@ VBase 是一个类似 **Supabase** 的 **Backend-as-a-Service (BaaS)** 平台,
--- ---
## 3. 目录结构 ## 3. 部署模式VBase 作为产品交付
VBase 设计为可私有化部署的产品,支持两种交付模式:
### 3.1 模式一:托管部署(你帮客户部署运维)
```
┌─────────────────────────────────────────────────────────────┐
│ 你的云基础设施 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 客户A实例 │ │ 客户B实例 │ │ 客户C实例 │ │
│ │ (2C产品) │ │ (2B产品) │ │ (混合产品) │ │
│ │ │ │ │ │ │ │
│ │ DB: A_db │ │ DB: B_db │ │ DB: C_db │ │
│ │ Redis: A_1 │ │ Redis: B_1 │ │ Redis: C_1 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
**特点:**
- 你在自己的云基础设施上为客户部署独立的 VBase 实例
- 每个实例完全隔离(独立数据库、独立 Redis
- 你负责运维,客户只管使用
- 可按照实例数量、资源使用量计费
**适用客户:** 没有运维能力的小团队,希望快速使用
### 3.2 模式二:客户自托管(客户自己部署)
```
┌─────────────────────────────────────────────────────────────┐
│ 客户 A 的基础设施 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ VBase 实例 │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 用户认证 │ │ 权限管理 │ │ │
│ │ │ (2C用户) │ │ (2B组织) │ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 数据库资源 │ │ 存储资源 │ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
**特点:**
- 客户在自己的环境中部署 VBase云服务器、私有云、K8s
- 数据完全属于客户,与你无关
- 客户自己运维,或者购买你的运维支持服务
- 通常按许可License或订阅模式收费
**适用客户:** 有数据合规要求的企业,有自己运维能力的团队
### 3.3 两种模式的对比
| 维度 | 托管部署 | 客户自托管 |
|------|----------|------------|
| **部署位置** | 你的云基础设施 | 客户的基础设施 |
| **数据归属** | 客户拥有,你代管 | 客户完全拥有 |
| **运维责任** | 你负责 | 客户负责 |
| **计费模式** | 按用量/实例数 | 按 License/订阅 |
| **定制化** | 受限 | 完全可定制 |
| **网络要求** | 需要公网访问 | 可内网部署 |
### 3.4 关键设计:完全隔离
无论哪种模式,**每个 VBase 实例都是完全独立的**
```go
// 实例级别的完全隔离
// - 独立的数据库连接
// - 独立的 Redis 命名空间
// - 独立的 JWT 密钥
// - 独立的配置
type VBaseInstance struct {
InstanceID string // 实例唯一标识
DatabaseDSN string // 独立数据库
RedisPrefix string // Redis 前缀隔离
JWTSecret string // 独立 JWT 密钥
Config InstanceConfig
}
```
这种设计确保:
1. 客户 A 的数据与客户 B 完全隔离
2. 一个实例的故障不影响其他实例
3. 客户可以独立升级、备份、迁移自己的实例
---
## 4. 目录结构
``` ```
vbase/ vbase/
@ -318,6 +456,95 @@ VBase 中的 "Org" 概念灵活适配不同场景:
└── 项目3 (level=2, Org) └── 项目3 (level=2, Org)
``` ```
### 4.4 典型客户场景示例
以下示例展示 VBase 作为产品交付的完整链路:
#### 示例1: 2C 产品公司(社交 App
```
VBase 提供商)
├─ 售卖 VBase 实例给「社交App公司」
客户社交App公司2C产品
├─ 部署 VBase 实例到自己的服务器(自托管模式)
├─ 技术负责人配置 VBase
│ ├─ 开启 App 用户注册/登录
│ ├─ 配置数据库存储用户资料
│ └─ 设置存储桶保存用户头像
终端用户:社交 App 的普通用户
├─ 注册账号(存储在 VBase
├─ 登录获取 JWT Token
├─ 上传头像到 VBase 存储
└─ 查询好友列表VBase 数据库)
```
**关键点:**
- 社交App公司的用户数据完全在自己的 VBase 实例中
- 你作为 VBase 提供商,接触不到终端用户数据
- 社交App公司按需购买 License 或订阅服务
#### 示例2: 2B 产品公司SaaS 软件)
```
VBase 提供商)
├─ 托管部署 VBase 实例给「企业SaaS公司」
│ (部署在你的云服务器上)
客户企业SaaS公司2B产品
├─ 使用 VBase 管理自己的企业客户
│ ├─ 每个企业客户 = VBase 中的一个 Org
│ ├─ 企业内的部门 = Org 下的子组织
│ └─ 企业员工 = OrgMember
终端用户SaaS 软件的企业用户
├─ 企业 A 的员工使用 VBase 登录 SaaS
├─ 按角色分配权限(管理员/普通员工)
└─ 企业间的数据通过 VBase 完全隔离
```
**关键点:**
- SaaS 公司用 VBase 做租户隔离(多租户架构)
- 你帮 SaaS 公司运维 VBase 实例,按实例数/用户量收费
- SaaS 公司的终端企业用户与你无直接关系
#### 示例3: 混合产品公司2C + 2B
```
VBase 提供商)
├─ 售卖两个 VBase 实例给「电商平台公司」
│ (一个给 C 端,一个给 B 端管理后台)
客户:电商平台公司(混合产品)
├─ 实例1C 端用户系统
│ ├─ 消费者注册/登录
│ ├─ 购物车、订单数据
│ └─ 用户画像存储
└─ 实例2B 端商家管理系统
├─ 商家入驻/审核
├─ 商家员工权限管理
└─ 运营数据分析
```
**关键点:**
- 同一客户的不同业务线可以用独立 VBase 实例
- 完全物理隔离,符合数据合规要求
- 你提供统一的管理控制台给客户技术团队
#### 数据隔离 #### 数据隔离
- **项目隔离**: 每个 Org 是独立的资源边界 - **项目隔离**: 每个 Org 是独立的资源边界
@ -325,7 +552,53 @@ VBase 中的 "Org" 概念灵活适配不同场景:
- **资源归属**: 所有资源通过 `org_id` 归属到具体项目 - **资源归属**: 所有资源通过 `org_id` 归属到具体项目
- **跨项目访问**: 需要显式授权,默认隔离 - **跨项目访问**: 需要显式授权,默认隔离
### 4.4 OAuth2.0 服务端 ### 4.5 BaaS 资源管理模块
作为 Supabase-like BaaS 平台VBase 提供以下后端资源管理能力:
#### 资源类型
| 资源类型 | 说明 | 典型操作 |
|----------|------|----------|
| **Database** | 数据库表、集合 | 创建表、查询、修改结构、删除表 |
| **Storage** | 文件存储 | 上传、下载、删除、管理存储桶 |
| **Function** | 边缘函数/云函数 | 部署、调用、更新、删除 |
| **API Key** | 访问密钥 | 创建、删除、刷新、权限绑定 |
#### 资源权限模型
```
项目 (Org)
├── 资源组 (Resource Group)
│ ├── 数据库资源
│ │ ├── table_1 (owner: user_a)
│ │ └── table_2 (owner: user_b)
│ ├── 存储资源
│ │ ├── bucket_images (public)
│ │ └── bucket_private (private)
│ └── 函数资源
│ ├── function_api (callable)
│ └── function_cron (internal)
```
#### 资源访问控制
```go
// 资源操作前检查权限
func AccessResource(userID, orgID, resourceType, action string) error {
checker := service.NewPermissionChecker()
result, err := checker.Check(userID, orgID, resourceType, action, nil)
if err != nil || !result.Allowed {
return vigo.ErrForbidden.WithString(result.Reason)
}
// 额外检查资源级别的细粒度权限
// 例如:只能修改自己创建的表
return nil
}
```
### 4.5 OAuth2.0 服务端
#### 支持的授权流程 #### 支持的授权流程

@ -161,79 +161,105 @@ type Role struct {
|------|------|----------| |------|------|----------|
| "" | 无条件,始终匹配 | 通用权限 | | "" | 无条件,始终匹配 | 通用权限 |
| "owner" | 资源所有者 | 只能操作自己的数据 | | "owner" | 资源所有者 | 只能操作自己的数据 |
| "org_member" | 组织成员 | 组织内数据访问 | | "org_member" | 项目成员 | 项目内数据访问 |
| "org_owner" | 组织所有者 | 所有者权限判断 | | "org_owner" | 项目所有者 | 项目所有者权限判断 |
--- ---
## 3. 权限检查流程 ## 3. 权限检查流程
### 3.1 流程图 ### 3.1 权限检查流程
根据是否有项目上下文 (`org_id`),权限检查分为两种方式:
#### 流程 A: 平台级权限检查 (无项目上下文)
``` ```
┌─────────────────┐ ┌─────────────────────────────┐
│ 请求进入 │ │ 请求进入 (无 org_id) │
│ user, org, │ │ user, resource, action │
│ resource, action│ └────────────┬────────────────┘
└────────┬────────┘
┌─────────────────┐ 命中 ┌─────────────────┐ ┌─────────────────────────────┐ 命中 ┌─────────────────┐
│ 检查缓存 │────────────→│ 返回缓存结果 │ │ 检查缓存 │────────────→│ 返回缓存结果 │
│ Redis │ │ allow/deny │ └────────────┬────────────────┘ └─────────────────┘
└────────┬────────┘ └─────────────────┘
│ 未命中 │ 未命中
┌─────────────────┐ ┌─────────────────────────────┐
│ 1. 检查组织所有者 │────────┐ │ 1. 检查是否是资源所有者 │
└────────┬────────┘ │ │ owner_id == user_id │
│ 是 │ └────────────┬────────────────┘
▼ │ │ 是
┌──────────┐ │
│ 返回 Allow│────────────┘ ┌──────────┐
│ 返回 Allow│
└──────────┘ └──────────┘
│ 否 │ 否
┌─────────────────┐ ┌─────────────────────────────┐
│ 2. 获取用户角色 │ │ 2. 加载平台级默认策略 │
│ 从 OrgMember │ │ personal:* 策略 │
│ 获取 role_ids │ └────────────┬────────────────┘
└────────┬────────┘
┌─────────────────┐ ┌─────────────────────────────┐
│ 3. 获取角色策略 │ │ 3. 评估策略 (Deny优先) │
│ 解析所有策略 │ └────────────┬────────────────┘
│ 去重合并 │
└────────┬────────┘ ┌─────┴─────┐
▼ ▼
┌───────┐ ┌───────┐
│ Deny │ │ Allow │
└───────┘ └───────┘
```
#### 流程 B: 项目级权限检查 (有项目上下文)
```
┌─────────────────────────────┐
│ 请求进入 (有 org_id) │
│ user, org_id, resource... │
└────────────┬────────────────┘
┌─────────────────┐ ┌─────────────────────────────┐ 命中 ┌─────────────────┐
│ 4. 检查 Deny 策略│────────┐ │ 检查缓存 │────────────→│ 返回缓存结果 │
│ 高优先级优先 │ │ └────────────┬────────────────┘ └─────────────────┘
└────────┬────────┘ │ │ 未命中
│ 匹配 Deny │
▼ │
┌──────────┐ │
│返回 Deny │────────────┘
│ 缓存结果 │
└──────────┘
│ 无 Deny
┌─────────────────┐ ┌─────────────────────────────┐
│ 5. 检查 Allow 策略│────────┐ │ 1. 检查是否是项目所有者 │
└────────┬────────┘ │ │ org.owner_id == user_id │────────┐
│ 匹配 Allow │ └────────────┬────────────────┘ │
│ 是 │
▼ │ ▼ │
┌──────────┐ │ ┌──────────┐ │
│返回 Allow│────────────┘ │ 返回 Allow│───────────────────┘
│ 缓存结果 │
└──────────┘ └──────────┘
│ 无 Allow │ 否
┌─────────────────┐ ┌─────────────────────────────┐
│ 6. 默认拒绝 │────────→ 返回 Deny │ 2. 获取用户在项目的角色 │
└─────────────────┘ 缓存结果 │ 从 OrgMember 表查询 │
└────────────┬────────────────┘
┌─────────────────────────────┐
│ 3. 获取角色关联的策略 │
└────────────┬────────────────┘
┌─────────────────────────────┐
│ 4. 评估策略 (Deny优先) │
│ Deny策略 → Allow策略 │
└────────────┬────────────────┘
┌─────┴─────┐
▼ ▼
┌───────┐ ┌───────┐
│ Deny │ │ Allow │
└───────┘ └───────┘
``` ```
### 3.2 决策规则 ### 3.2 决策规则
@ -247,63 +273,134 @@ type Role struct {
## 4. 使用指南 ## 4. 使用指南
### 4.1 检查权限 ### 4.1 平台级权限检查
**代码示例:** **场景**:用户管理自己的账号、创建新项目
```go ```go
import "github.com/veypi/vbase/internal/service" // 检查用户是否可以更新自己的信息
// orgID 传空字符串,表示平台级检查
result, err := checker.Check(userID, "", "user", "update", map[string]any{
"owner_id": userID, // 传入自己的ID
})
// 结果:允许(满足 owner 条件)
// 检查用户是否可以创建新项目
result, err := checker.Check(userID, "", "org", "create", nil)
// 结果:允许(平台级默认策略允许创建项目)
// 检查用户是否可以更新其他用户信息
result, err := checker.Check(userID, "", "user", "update", map[string]any{
"owner_id": otherUserID, // 传入他人ID
})
// 结果:拒绝(不满足 owner 条件)
```
### 4.2 项目级权限检查
**场景**:在项目内操作资源
```go
// 检查用户在项目内是否有管理员权限
result, err := checker.Check(userID, "project-123", "member", "invite", nil)
// 结果取决于用户在 project-123 中的角色
// 项目所有者检查(快速路径)
// 如果 userID == org.OwnerID直接返回允许
// 普通成员检查
// 1. 查询 OrgMember 获取角色
// 2. 查询 Role 获取策略
// 3. 评估策略
```
func SomeHandler(x *vigo.X) error { ### 4.3 完整示例:更新用户信息
```go
func UpdateUser(x *vigo.X, req *UpdateRequest) error {
userID := middleware.CurrentUser(x) userID := middleware.CurrentUser(x)
orgID := middleware.CurrentOrg(x) targetUserID := req.UserID
checker := service.NewPermissionChecker() checker := service.NewPermissionChecker()
result, err := checker.Check(userID, orgID, "user", "update", map[string]any{
"owner_id": targetUserID,
})
// 场景1: 更新自己的信息(平台级)
if targetUserID == userID {
result, err := checker.Check(userID, "", "user", "update", map[string]any{
"owner_id": userID,
})
if err != nil || !result.Allowed { if err != nil || !result.Allowed {
return vigo.ErrForbidden.WithString(result.Reason) return vigo.ErrForbidden.WithString(result.Reason)
} }
// 执行更新...
return nil
}
// 继续处理... // 场景2: 管理员更新其他用户信息(需要平台级管理员权限)
result, err := checker.Check(userID, "", "user", "update", nil)
if err != nil || !result.Allowed {
return vigo.ErrForbidden.WithString("only admin can update other users")
}
// 执行更新...
return nil
} }
``` ```
### 4.2 创建自定义策略 ### 4.4 完整示例:项目内操作
```go ```go
policy := &model.Policy{ func DeleteProjectResource(x *vigo.X, req *DeleteResourceRequest) error {
Code: "custom:resource:action", userID := middleware.CurrentUser(x)
Name: "自定义策略", orgID := middleware.CurrentOrg(x) // 从请求头 X-Org-ID 获取
Description: "允许特定用户操作",
Resource: "resource_name", if orgID == "" {
Action: "action_name", // create/read/update/delete return vigo.ErrArgInvalid.WithString("org_id required")
Effect: model.EffectAllow,
Condition: "owner", // owner/org_member/空
Priority: 50,
} }
model.DB.Create(policy) checker := service.NewPermissionChecker()
// 检查用户在项目内是否有删除资源的权限
result, err := checker.Check(userID, orgID, "resource", "delete", map[string]any{
"resource_id": req.ResourceID,
})
if err != nil || !result.Allowed {
return vigo.ErrForbidden.WithString(result.Reason)
}
// 执行删除...
return nil
}
``` ```
### 4.3 创建角色并授权 ### 4.5 创建自定义策略
```go ```go
// 创建角色 // 项目级策略(需要关联到具体项目)
policy := &model.Policy{
Code: "custom:db:admin",
Name: "数据库管理员",
Description: "管理项目数据库",
Resource: "database",
Action: "*", // 所有操作
Effect: model.EffectAllow,
Condition: "", // 无条件限制
Scope: "project", // 项目级策略
OrgID: "project-123", // 所属项目
}
model.DB.Create(policy)
// 将策略添加到角色
role := &model.Role{ role := &model.Role{
OrgID: orgID, OrgID: "project-123",
Name: "部门管理员", Name: "DBAdmin",
Description: "管理部门成员", PolicyIDs: "custom:db:admin",
PolicyIDs: "policy1,policy2,policy3",
} }
model.DB.Create(role) model.DB.Create(role)
// 分配给用户 // 分配角色给用户
member := &model.OrgMember{ member := &model.OrgMember{
OrgID: orgID, OrgID: "project-123",
UserID: userID, UserID: "user-456",
RoleIDs: role.ID, RoleIDs: role.ID,
} }
model.DB.Create(member) model.DB.Create(member)
@ -381,19 +478,102 @@ Condition: "org_member"
SysPolicyRoleManage = "sys:role:manage" SysPolicyRoleManage = "sys:role:manage"
Resource: "role" Resource: "role"
Action: "*" Action: "*"
Condition: "" Condition: "admin"
// 读取策略 // 读取策略
SysPolicyPolicyRead = "sys:policy:read" SysPolicyPolicyRead = "sys:policy:read"
Resource: "policy" Resource: "policy"
Action: "read" Action: "read"
Condition: "" Condition: "org_member"
// 管理策略 // 管理策略
SysPolicyPolicyManage = "sys:policy:manage" SysPolicyPolicyManage = "sys:policy:manage"
Resource: "policy" Resource: "policy"
Action: "*" Action: "*"
Condition: "" Condition: "admin"
```
### 5.5 资源级策略BaaS 核心资源)
**数据库资源 (database)**
```go
// 查询数据库
SysPolicyDBRead = "sys:db:read"
Resource: "database"
Action: "read"
Condition: "org_member"
// 管理数据库(创建表、修改结构)
SysPolicyDBManage = "sys:db:manage"
Resource: "database"
Action: "*"
Condition: "developer"
```
**存储资源 (storage)**
```go
// 读取存储文件
SysPolicyStorageRead = "sys:storage:read"
Resource: "storage"
Action: "read"
Condition: "org_member"
// 上传/删除文件
SysPolicyStorageWrite = "sys:storage:write"
Resource: "storage"
Action: "create,update,delete"
Condition: "developer"
// 管理存储桶
SysPolicyStorageAdmin = "sys:storage:admin"
Resource: "storage"
Action: "*"
Condition: "admin"
```
**函数资源 (function)**
```go
// 调用函数
SysPolicyFunctionCall = "sys:function:call"
Resource: "function"
Action: "call"
Condition: "org_member"
// 管理函数(部署、删除)
SysPolicyFunctionManage = "sys:function:manage"
Resource: "function"
Action: "create,update,delete"
Condition: "developer"
```
**API 密钥管理 (apikey)**
```go
// 读取 API 密钥(只能读取自己创建的密钥)
SysPolicyAPIKeyRead = "sys:apikey:read"
Resource: "apikey"
Action: "read"
Condition: "owner"
// 管理 API 密钥
SysPolicyAPIKeyManage = "sys:apikey:manage"
Resource: "apikey"
Action: "*"
Condition: "developer"
```
### 5.6 平台超级管理员策略
```go
// 超级管理员 - 拥有所有权限
SysPolicySuperAdmin = "sys:super:admin"
Resource: "*"
Action: "*"
Condition: "is_super_admin"
Priority: 999
``` ```
--- ---
@ -440,18 +620,84 @@ service.ClearOrgPermissionCache(orgID)
2. **职责分离**: 敏感操作需要多个角色共同完成 2. **职责分离**: 敏感操作需要多个角色共同完成
3. **策略命名规范**: `{resource}:{action}:{condition}` 3. **策略命名规范**: `{resource}:{action}:{condition}`
### 7.2 角色设计 ### 7.2 BaaS 平台角色设计
VBase 作为 Supabase-like BaaS 平台,角色设计覆盖 **2C个人开发者****2B团队/企业** 场景:
#### 2C 个人开发者场景
```
个人项目角色体系:
├── owner (项目所有者)
│ └── 全部权限(可以删除项目)
└── developer (开发者)
└── 读写资源、调用 API
``` ```
组织层级角色体系:
个人开发者通常自己就是项目所有者,不需要复杂的角色体系。
#### 2B 团队协作场景
```
团队项目角色体系:
├── owner (所有者) ├── owner (所有者)
│ └── 全部权限 │ └── 全部权限、可删除项目、管理账单
├── admin (管理员) ├── admin (管理员)
│ └── 管理成员、角色、策略 │ └── 管理成员、角色、资源设置
├── manager (部门经理) ├── developer (开发者)
│ └── 管理部门成员 │ ├── 数据库: 创建表、查询、修改结构
└── member (普通成员) │ ├── 存储: 上传/下载文件、管理存储桶
└── 基础访问权限 │ ├── 函数: 部署、调用、删除函数
│ └── API密钥: 创建、管理
├── viewer (访客/只读)
│ └── 查看数据、只读访问
└── auditor (审计员 - 可选)
└── 查看日志、审计记录
```
#### 角色权限对照表
| 角色 | 成员管理 | 资源管理 | 数据读写 | API密钥 | 项目设置 |
|------|----------|----------|----------|---------|----------|
| **owner** | ✓ | ✓ | ✓ | ✓ | ✓ |
| **admin** | ✓ | ✓ | ✓ | ✓ | ✗ |
| **developer** | ✗ | ✓ | ✓ | ✓ | ✗ |
| **viewer** | ✗ | ✗ | 只读 | ✗ | ✗ |
#### 系统角色配置示例
```go
// Owner 角色 - 绑定所有权限
var RoleOwner = model.Role{
Name: "owner",
Description: "项目所有者",
PolicyIDs: "sys:org:admin,sys:member:manage,sys:role:manage,sys:policy:manage",
IsSystem: true,
}
// Admin 角色 - 管理权限
var RoleAdmin = model.Role{
Name: "admin",
Description: "项目管理员",
PolicyIDs: "sys:member:manage,sys:role:read,sys:db:manage,sys:storage:admin,sys:function:manage",
IsSystem: true,
}
// Developer 角色 - 开发权限
var RoleDeveloper = model.Role{
Name: "developer",
Description: "开发者",
PolicyIDs: "sys:db:manage,sys:storage:write,sys:function:manage,sys:apikey:manage",
IsSystem: true,
}
// Viewer 角色 - 只读权限
var RoleViewer = model.Role{
Name: "viewer",
Description: "访客",
PolicyIDs: "sys:org:read,sys:db:read,sys:storage:read,sys:function:call",
IsSystem: true,
}
``` ```
### 7.3 权限检查位置 ### 7.3 权限检查位置
@ -478,7 +724,79 @@ func UpdateUser(userID string, data map[string]any) error {
} }
``` ```
### 7.4 权限测试 ### 7.4 BaaS 平台权限场景示例
**场景1: 个人开发者创建项目**
```go
// 小明是个人开发者,注册后创建项目
// 1. 创建项目(平台级权限检查)
result, _ := checker.Check("xiaoming_user_id", "", "org", "create", nil)
// 结果: 允许personal:org:create 策略)
// 2. 小明成为项目所有者
// org.owner_id = "xiaoming_user_id"
// 3. 小明在项目内操作数据库(项目级权限)
result, _ = checker.Check("xiaoming_user_id", "my-project", "database", "create", nil)
// 结果: 允许(小明是项目所有者)
```
**场景2: 团队协作开发**
```go
// CEO 创建 WebApp 项目,邀请 CTO 为管理员,员工为开发者
// - CEO: owner
// - CTO: admin
// - 员工A: developer
// - 外包人员: viewer
// CTO 邀请成员(有 member:manage 权限)
result, _ := checker.Check("cto_user_id", "webapp-project", "member", "create", nil)
// 结果: 允许admin 角色有 member:manage 策略)
// 员工A 创建数据库表(有 db:manage 权限)
result, _ = checker.Check("employee_a_id", "webapp-project", "database", "create", nil)
// 结果: 允许developer 角色有 db:manage 策略)
// 外包人员 尝试删除表viewer 没有 delete 权限)
result, _ = checker.Check("contractor_id", "webapp-project", "database", "delete", nil)
// 结果: 拒绝viewer 只有 db:read 权限)
```
**场景3: API 密钥访问控制**
```go
// 开发者创建 API 密钥用于后端服务
// 只能查看自己创建的密钥
result, _ := checker.Check("developer_id", "project-123", "apikey", "read", map[string]any{
"owner_id": "developer_id",
})
// 结果: 允许(满足 owner 条件)
// 尝试查看他人创建的密钥
result, _ = checker.Check("developer_id", "project-123", "apikey", "read", map[string]any{
"owner_id": "other_developer_id",
})
// 结果: 拒绝(不满足 owner 条件)
```
**场景4: 跨项目资源访问**
```go
// 用户小明在 project-A 是开发者,在 project-B 是访客
// 在 project-A 上传文件
result, _ := checker.Check("xiaoming_id", "project-A", "storage", "create", nil)
// 结果: 允许developer 角色有 storage:write 权限)
// 在 project-B 上传文件
result, _ = checker.Check("xiaoming_id", "project-B", "storage", "create", nil)
// 结果: 拒绝viewer 角色只有 storage:read 权限)
```
### 7.5 权限测试
```go ```go
func TestPermissionCheck(t *testing.T) { func TestPermissionCheck(t *testing.T) {
@ -531,11 +849,20 @@ func TestPermissionCheck(t *testing.T) {
**检查步骤:** **检查步骤:**
**平台级权限检查失败org_id 为空):**
1. 确认用户已登录 1. 确认用户已登录
2. 确认用户是组织成员 2. 确认操作的是自己的资源(检查 owner_id 条件)
3. 检查用户角色 3. 检查用户是否有平台级管理员权限
4. 检查角色绑定的策略 4. 检查默认个人策略是否生效
5. 检查策略的 Effect 和 Condition
**项目级权限检查失败(有 org_id:**
1. 确认用户是项目成员OrgMember 状态为 active
2. 检查用户角色是否正确分配
3. 检查角色绑定的策略
4. 检查策略的 Effect 和 Condition
5. 确认资源所属的项目是否正确
**调试日志:** **调试日志:**
@ -584,7 +911,9 @@ func (pc *PermissionChecker) evaluateCondition(p *model.Policy, userID, orgID st
} }
``` ```
### 9.2 添加资源类型 ### 9.2 添加 BaaS 资源类型
**步骤1: 定义资源常量**
```go ```go
// 在 policy.go 中添加资源常量 // 在 policy.go 中添加资源常量
@ -592,10 +921,74 @@ const (
ResourceUser = "user" ResourceUser = "user"
ResourceOrg = "org" ResourceOrg = "org"
ResourceMember = "member" ResourceMember = "member"
ResourceCustom = "custom_resource" // 新增 ResourceDatabase = "database"
ResourceStorage = "storage"
ResourceFunction = "function"
ResourceAPIKey = "apikey"
ResourceCustom = "custom_resource" // 新增资源类型
) )
``` ```
**步骤2: 创建资源级策略**
```go
// 为新增资源创建策略
func (pc *PermissionChecker) getCustomResourcePolicies() []model.Policy {
return []model.Policy{
{
Code: "custom:read",
Name: "读取自定义资源",
Resource: ResourceCustom,
Action: "read",
Effect: model.EffectAllow,
Condition: "org_member",
},
{
Code: "custom:manage",
Name: "管理自定义资源",
Resource: ResourceCustom,
Action: "create,update,delete",
Effect: model.EffectAllow,
Condition: "developer",
},
}
}
```
**步骤3: 在角色中使用**
```go
// 创建新角色使用自定义策略
customRole := &model.Role{
OrgID: orgID,
Name: "custom_manager",
Description: "自定义资源管理员",
PolicyIDs: "custom:read,custom:manage",
Scope: "resource",
}
```
### 9.3 多租户资源隔离
在 BaaS 平台中,资源需要严格的项目隔离:
```go
// 查询时自动添加 org_id 过滤
func ListResources(userID, orgID string) ([]Resource, error) {
// 检查用户在项目中的权限
checker := service.NewPermissionChecker()
result, err := checker.Check(userID, orgID, "custom_resource", "read", nil)
if err != nil || !result.Allowed {
return nil, vigo.ErrForbidden
}
// 查询该项目的资源(自动隔离)
var resources []Resource
err = model.DB.Where("org_id = ?", orgID).Find(&resources).Error
return resources, err
}
```
--- ---
## 10. 参考 ## 10. 参考

Loading…
Cancel
Save