From 438a84d9fc375ee3ee0dfea1d1874545fea43b52 Mon Sep 17 00:00:00 2001 From: veypi Date: Wed, 25 Feb 2026 18:12:57 +0800 Subject: [PATCH] docs: Update documentation to reflect scoped RBAC and remove org system - Update CLAUDE.md to describe scoped RBAC instead of multi-tenant org - Simplify README.md removing org-related features - Update auth.md with comprehensive scoped permission documentation - Remove configuration.md (merged into other docs) - Update design.md with new architecture decisions - Update integration.md with scoped auth examples - Update UI documentation removing org references - Update test README removing org test references --- CLAUDE.md | 104 ++--------- README.md | 187 +------------------ docs/auth.md | 389 +++++++++++++++++++++++++++++----------- docs/configuration.md | 297 ------------------------------ docs/design.md | 117 +++--------- docs/integration.md | 274 ++++++++-------------------- docs/todo.md | 6 +- docs/ui.md | 106 ++--------- scripts/tests/README.md | 23 +-- tests/README.md | 2 - 10 files changed, 434 insertions(+), 1071 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2b53784..d872f9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,12 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -VBase is a Go-based identity authentication and permission management framework built on the [Vigo](https://github.com/veypi/vigo) web framework (onion-model middleware architecture). It provides user management, organization (multi-tenant), RBAC permissions, and OAuth2 authentication services. +VBase is a Go-based identity authentication and permission management framework built on the [Vigo](https://github.com/veypi/vigo) web framework (onion-model middleware architecture). It provides user management, scoped RBAC permissions, and OAuth2 authentication services. - **Language**: Go 1.24+ - **Framework**: Vigo (onion-model middleware) - **ORM**: GORM (MySQL, PostgreSQL, SQLite supported) - **Authentication**: JWT + OAuth2 +- **Permissions**: Scoped RBAC (Role-Based Access Control) - **Frontend**: vhtml (embedded HTML-based UI at `/vb/`) ## Common Commands @@ -26,8 +27,6 @@ go run ./cli/main.go db drop go test -v ./tests/... ``` -Tests in `tests/` use an in-memory SQLite database with mock Redis. The `ensureUsers(t)` helper sets up test users (admin, user1, user2) with tokens stored in globals (`AdminToken`, `User1Token`, etc.). - ## Architecture ### Onion Model Request Flow @@ -38,30 +37,22 @@ Request -> [Global Before Middlewares] -> [Router] -> [Handler] -> [Service] -> Response <- [Global After Middleware] <--------+ ``` -Key middleware stages: - -- **Before**: Authentication, preprocessing, context injection (parent hooks run before child hooks) -- **Handler**: Business logic, returns data (does not write response directly) -- **After**: Response formatting (parent hooks run after child hooks) - ### Directory Structure ``` ├── api/ # REST API handlers and routing -│ ├── auth/ # Login, register, refresh token, SMS +│ ├── auth/ # Login, register, refresh token │ ├── oauth/ # OAuth2 provider endpoints -│ ├── org/ # Organization/tenant management │ ├── role/ # Role management │ ├── user/ # User management │ └── init.go # Router aggregation -├── auth/ # Core RBAC permission system +├── auth/ # Core Scoped RBAC permission system │ ├── auth.go # Permission checking implementation -│ └── middleware.go # Auth middleware +│ └── design.md # Permission system design doc ├── cfg/ # Configuration (DB, Redis, JWT settings) ├── models/ # GORM data models -│ ├── auth.go # Role, Policy, UserRole models +│ ├── auth.go # Role, Permission, UserRole models │ ├── user.go # User, Identity, Session models -│ ├── org.go # Org, OrgMember models │ └── init.go # Model registration and migrations ├── libs/ # Utilities (cache, crypto, jwt, sms, email) ├── ui/ # Frontend admin interface (vhtml framework) @@ -69,96 +60,39 @@ Key middleware stages: └── tests/ # Go integration tests ``` -### Permission System (RBAC) - -Permission format: `resource:action` or `app:resource:action` +### Permission System (Scoped RBAC) -Examples: `user:read`, `org:create`, `oauth-client:delete` +The system uses a scoped permission model where permissions are isolated by `Scope` (e.g., "vb" for VBase, "app1" for external apps). -**Important**: Resource identifiers must NOT contain colons (use kebab-case or snake_case). +**Permission Format**: `resource:instance:sub-resource:sub-instance` (Tree structure) -Permission middleware usage: - -```go -// Basic permission -Router.Post("/articles", AppAuth.Perm("article:create"), createArticle) - -// Owner check - allows if user is resource owner -Router.Patch("/articles/{id}", AppAuth.PermWithOwner("article:update", "id"), updateArticle) - -// Wildcard support -AppAuth.AddRole("admin", "Admin", "*:*") // All permissions -``` +**Levels**: +- Level 1: Create (Odd layers) +- Level 2: Read (Even layers) +- Level 4: Write (Even layers) +- Level 7: Admin (Even layers, inherited downwards) -### Multi-Tenancy (Org) - -Organizations provide data isolation. Three usage patterns: - -1. **B2C (Single Tenant)**: Ignore Org, bind roles to global (`org_id=""`) -2. **B2B SaaS (Multi-Tenant)**: Require `X-Org-ID` header on all business APIs -3. **Platform (Hybrid)**: Merchant side uses Org, consumer side is global - -The `AuthMiddleware` extracts `X-Org-ID` header and loads user's roles for that org context. +**Key Interfaces**: +- `auth.Factory.New(scope)`: Get scoped auth instance. +- `auth.PermRead(code)`, `auth.PermWrite(code)`: Middleware checks. +- `auth.Grant(ctx, userID, permID, level)`: Grant permission. ### API Response Format All responses are JSON formatted by `common.JsonResponse` middleware: **Success:** - ```json {"code": 200, "data": { ... }} ``` **Error:** - ```json { "code": 40001, "message": "Error description" } ``` -Error codes combine HTTP status (3 digits) + scenario (2 digits), e.g., `40001` = Bad Request + invalid argument. - -### Configuration - -Configuration is loaded from: - -1. Config file (`-f ./cfg/dev.yml`) -2. Environment variables (uppercase with underscores, e.g., `DB_DSN`, `JWT_SECRET`) - -Key config in `cfg/cfg.go`: - -- `DB`: Database connection (type: mysql/postgres/sqlite) -- `Redis`: Use `memory` for development -- `Key`: System encryption key (32+ chars recommended) -- `JWT`: Token expiry settings -- `InitAdmin`: Auto-create admin on first run (empty password = first registered user becomes admin) - -### Handler Pattern (Vigo Framework) - -Handlers use generics with automatic parameter binding: - -```go -type CreateReq struct { - Name string `json:"name" src:"json"` // Required - Email *string `json:"email" src:"json"` // Optional (pointer) - Page int `src:"query" default:"1"` // Query param with default -} - -func CreateUser(x *vigo.X, req *CreateReq) (*User, error) { - // Business logic - return user, nil // Framework handles JSON response -} -``` - -Parameter sources: `path`, `query`, `header`, `json`, `form`. Non-pointer fields are required by default. - ### Frontend (vhtml) The admin UI is in `ui/` using the vhtml framework: - -- Pages in `ui/page/` (e.g., `user_list.html` → route `/user_list`) -- Components as HTML files, referenced with hyphens (e.g., `` for `/ui/form/user_create.html`) -- Routes defined in `ui/routes.js` - Access UI at `/vb/` path when server is running - -Full API documentation is available at `/_api.json` when the server is running. +- Routes defined in `ui/routes.js` diff --git a/README.md b/README.md index f083fdc..7cab127 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,13 @@ ## 简介 -**VBase** 是一个基于 [Vigo](https://github.com/veypi/vigo) 框架开发的高性能后端基础框架,提供一套标准化的用户管理、组织架构(多租户)、权限控制(RBAC)和 OAuth2 认证服务。可作为独立服务部署,也可作为基础库集成到你的 Go 项目中。 +**VBase** 是一个基于 [Vigo](https://github.com/veypi/vigo) 框架开发的高性能后端基础框架,提供一套标准化的用户管理、作用域权限控制(Scoped RBAC)和 OAuth2 认证服务。可作为独立服务部署,也可作为基础库集成到你的 Go 项目中。 ## 核心特性 - 🔐 **完整认证体系** - JWT Token 认证(Access + Refresh)、多因素认证(短信验证码) -- 🛡️ **RBAC 权限控制** - 基于角色的访问控制,支持资源级权限和通配符权限 -- 🏢 **多租户架构** - 组织级别的数据隔离,灵活适配 B2C/B2B/平台型业务 +- 🛡️ **Scoped RBAC 权限控制** - 基于作用域(Scope)的角色访问控制,支持资源级权限和通配符权限 +- � **层级权限管理** - 支持资源类型(奇数层)和实例(偶数层)的精细化权限控制 - 🔑 **OAuth2 Provider** - 完整的 OAuth2 服务端实现,支持第三方应用接入 - 🗄️ **多数据库支持** - MySQL、PostgreSQL、SQLite 自动适配 - 📱 **内置管理界面** - 基于 vhtml 的嵌入式管理后台 @@ -90,191 +90,12 @@ vbase/ ├── api/ # REST API 接口层 │ ├── auth/ # 认证接口(登录、注册、Token 刷新) │ ├── oauth/ # OAuth2 Provider 接口 -│ ├── org/ # 组织/租户管理 │ ├── role/ # 角色管理 │ └── user/ # 用户管理 -├── auth/ # 核心权限控制模块(RBAC 实现) +├── auth/ # 核心权限控制模块(Scoped RBAC 实现) ├── cfg/ # 配置管理 ├── cli/ # 命令行入口 ├── models/ # 数据模型(GORM) ├── ui/ # 前端管理界面(vhtml) └── docs/ # 文档 ``` - -## 配置说明 - -VBase 支持通过配置文件或环境变量进行配置: - -```yaml -# 数据库配置 -dsn: "root:password@tcp(127.0.0.1:3306)/vbase?charset=utf8&parseTime=True" -db: "mysql" # 可选: mysql, postgres, sqlite - -# JWT 配置 -jwt: - secret: "your-secret-key-min-32-characters" - access_expiry: "1h" - refresh_expiry: "720h" - -# 应用配置 -app: - id: "myapp" - name: "My Application" - init_admin: - username: "admin" - password: "admin123" - email: "admin@example.com" - -# OAuth2 提供商配置 -providers: - github: - enabled: true - client_id: "your-github-client-id" - client_secret: "your-github-client-secret" -``` - -环境变量命名规则:直接使用配置项的大写下划线形式,例如 `JWT_SECRET`、`PROVIDERS_GITHUB_CLIENT_ID`。 - -## 权限系统 - -### 基础用法 - -```go -// 创建应用专属的权限实例 -var AppAuth = vbase.Auth.New("myapp") - -func init() { - // 定义角色 - AppAuth.AddRole("admin", "管理员", "*:*") - AppAuth.AddRole("editor", "编辑", "article:create", "article:update") -} - -// 使用权限中间件保护路由 -Router.Post("/articles", "创建文章", AppAuth.Perm("article:create"), createArticle) -Router.Patch("/articles/{id}", "更新文章", AppAuth.PermWithOwner("article:update", "id"), updateArticle) -``` - -### 权限格式 - -- `resource:action` - 基础格式,如 `user:read`, `org:create` -- `app:resource:action` - 带应用前缀,如 `myapp:article:delete` -- `resource:*` - 通配符权限,匹配资源的所有操作 - -更多权限用法请参考 [集成文档](./docs/integration.md)。 - -## API 概览 - -### 认证接口 - -| 方法 | 路径 | 描述 | -|------|------|------| -| POST | `/vb/api/auth/login` | 用户登录 | -| POST | `/vb/api/auth/register` | 用户注册 | -| POST | `/vb/api/auth/refresh` | 刷新 Token | -| POST | `/vb/api/auth/logout` | 退出登录 | -| POST | `/vb/api/auth/sms/send` | 发送短信验证码 | -| POST | `/vb/api/auth/sms/login` | 短信验证码登录 | - -### 用户管理 - -| 方法 | 路径 | 描述 | -|------|------|------| -| GET | `/vb/api/user/info` | 获取当前用户信息 | -| PATCH | `/vb/api/user/info` | 更新用户信息 | -| GET | `/vb/api/users` | 获取用户列表(管理员) | - -### 组织管理 - -| 方法 | 路径 | 描述 | -|------|------|------| -| POST | `/vb/api/orgs` | 创建组织 | -| GET | `/vb/api/orgs` | 获取组织列表 | -| GET | `/vb/api/orgs/{id}` | 获取组织详情 | -| POST | `/vb/api/orgs/{id}/members` | 添加组织成员 | -| GET | `/vb/api/orgs/{id}/members` | 获取组织成员列表 | - -### OAuth2 接口 - -| 方法 | 路径 | 描述 | -|------|------|------| -| GET | `/vb/api/oauth/authorize` | 授权端点 | -| POST | `/vb/api/oauth/token` | Token 端点 | -| GET | `/vb/api/userinfo` | 用户信息端点 | - -完整 API 文档请参考 [API 文档](./docs/api.md)。 - -## 多租户场景支持 - -VBase 的组织(Org)设计灵活,支持多种业务模式: - -| 场景 | 特点 | Org 使用方式 | -|------|------|--------------| -| **B2C 应用** | 单租户,所有用户直接面对平台 | 可选,权限绑定到全局 | -| **B2B SaaS** | 多租户,数据严格隔离 | 强制使用,请求需携带 `X-Org-ID` | -| **平台型** | 平台 + 商家 + 消费者 | 商家端使用 Org,消费者端可选 | - -## 架构设计 - -VBase 采用洋葱模型和分层架构: - -``` -Request -> [Global Middlewares] -> [Router] -> [Group Middlewares] - -> [Handler] - -> [Service/Logic] - -> [Model/DAO] -> Database - | -Response <- [Global After Middleware] <-------------+ -``` - -详细架构说明请参考 [架构设计文档](./docs/design.md)。 - -## 开发 - -### 运行测试 - -```bash -# 运行集成测试 -./scripts/tests/run_all.sh - -# 或单独运行测试 -./scripts/tests/01_basic_auth.sh -``` - -### 构建 - -```bash -go build -o vbase cli/main.go -``` - -### 命令行子命令 - -```bash -# 生成配置文件 -go run ./cli/main.go gen_cfg - -# 数据库操作 -go run ./cli/main.go db [migrate|seed|...] -``` - -## 技术栈 - -- **语言**: Go 1.24+ -- **Web 框架**: [Vigo](https://github.com/veypi/vigo) (洋葱模型) -- **ORM**: GORM -- **认证**: JWT + OAuth2 -- **前端**: vhtml/vhtml-ui -- **数据库**: MySQL / PostgreSQL / SQLite - -## 贡献 - -欢迎提交 Issue 和 Pull Request! - -## 许可证 - -[Apache License 2.0](./LICENSE) - ---- - -

- Made with ❤️ by veypi -

diff --git a/docs/auth.md b/docs/auth.md index 7c31f43..ed9bd37 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,156 +1,341 @@ -# 鉴权与授权模块设计 (Authentication & Authorization) +# Auth 权限系统设计 -`auth` 模块为 VBase 应用提供了灵活且强大的权限控制系统。它摒弃了隐式的“所有权猜测”,转而采用**显式授权**(ACL)和**手动鉴权**相结合的策略,以确保系统的安全性和可维护性。 +--- -## 1. 核心鉴权机制概览 +## 一、权限码层级 -我们提供三种层级的鉴权方式,分别适用于不同的业务场景: +### 1.1 层级定义 -| 方式 | 描述 | 适用场景 | 示例 | -| :--- | :--- | :--- | :--- | -| **全局中间件** (`Perm`) | 检查用户是否拥有某种**全局能力**(基于角色)。 | 管理后台、列表查询、无需特定资源ID的操作。 | `user:read` (查看所有用户) | -| **简单手动鉴权** (Manual) | 在业务代码中直接检查资源字段(如 `OwnerID`)。 | **高频/私有资源**(如订单、日志),逻辑简单且追求高性能。 | 修改自己的订单 | -| **复杂资源鉴权** (`PermOnResource`) | 基于数据库 ACL 表检查用户对**特定实例**的权限。 | **高价值/共享资源**(如项目、组织),需要精细控制和跨用户授权。 | 修改项目成员 | +``` +层级从 1 开始计数: +- 奇数层(第1、3、5层):资源类型 +- 偶数层(第2、4、6层):实例 +``` + +### 1.2 示例 + +``` +app → 第1层 (奇数) - 资源类型 +app:vbase → 第2层 (偶数) - 实例 +app:vbase:role → 第3层 (奇数) - 资源类型 +app:vbase:role:admin → 第4层 (偶数) - 实例 +``` --- -## 2. 基础:上下文与中间件 +## 二、权限等级 -### 2.1 认证中间件 (AuthMiddleware) +### 2.1 奇数层(资源类型) -认证中间件仅负责验证 JWT Token 的有效性,并将核心的用户 ID 注入到请求上下文中。为了保持高性能,它**不会**预加载用户详情、角色或组织信息。 +| level | 二进制 | 含义 | +| ----- | ------ | -------------------- | +| 0 | 000 | 无权限 | +| 1 | 001 | 可创建该类型的子资源 | -### 2.2 上下文访问 +### 2.2 偶数层(实例) -请使用 `auth` 包提供的辅助函数来访问上下文中的认证信息: +| level | 二进制 | 含义 | +| ----- | ------ | ---------------------- | +| 0 | 000 | 无权限 | +| 2 | 010 | 读取 | +| 4 | 100 | 写入(修改,不能删除) | +| 6 | 110 | 读写(读取+修改) | +| 7 | 111 | 管理员(完全控制:读写+删除+授权) | -```go -func MyHandler(x *vigo.X) { - // 1. 获取当前用户 ID (核心,所有认证请求都可用) - userID := auth.GetUserID(x) - - if userID == "" { - // 未登录 - return vigo.ErrUnauthorized - } - - // 2. 获取当前组织 ID - // 注意:仅当路由使用了 LoadOrg 中间件,或手动调用了 LoadOrg 后才可用 - orgID := auth.GetOrgID(x) - - // 3. 获取在当前组织中的角色列表 - // 注意:仅当路由使用了 LoadOrg 中间件后可用 - roles := auth.GetOrgRoles(x) -} -``` +--- -### 2.3 组织上下文加载 (LoadOrg) +## 三、检查规则 -对于需要组织上下文的接口(如 `/api/orgs/{org_id}/...`),使用 `LoadOrg` 中间件按需加载组织信息。 +### 3.1 层级与权限对应 -- **行为**: 自动从 Path (`{org_id}`), Query (`?org_id=`), Header (`X-Org-ID`) 中解析组织 ID。 -- **验证**: 检查当前用户是否为该组织的有效成员。 -- **注入**: 将 OrgID 和用户在该组织的角色注入上下文。 +| 权限 | level | 检查层级 | 说明 | +|------|-------|----------|------| +| 创建 | 1 | 奇数层 | 检查资源类型层 | +| 读取 | 2 | 偶数层 | 检查实例层 | +| 写入 | 4 | 偶数层 | 检查实例层 | +| 读写 | 6 | 偶数层 | 检查实例层 | +| 管理 | 7 | 偶数层 | 检查实例层 | -```go -// 路由注册示例 -// 对于需要组织上下文的接口,显式添加 LoadOrg 中间件 -Router.Get("/{org_id}", "获取组织详情", auth.VBaseAuth.LoadOrg, auth.VBaseAuth.Perm("org:read"), get) +### 3.2 具体规则 + +``` +创建资源 (level 1) + → 检查当前 permissionID 对应的奇数层 + → 例: "app:{appID}:role" 检查 "app:{appID}:role" 层 + +读取/更新/删除资源 (level 2,4,6,7) + → 检查当前 permissionID 对应的偶数层 + → 如无权限,递归向上检查父实例层 + → 注意:只有 Level 7 (管理员) 权限才会向下继承,Level 2,4,6 不会继承 + → 例: "app:{appID}:role:{roleID}" 先检查实例层,再检查 "app:{appID}" ``` --- -## 3. 场景一:全局/类别权限 (Perm 中间件) +## 四、权限流程示例 -用于控制“谁能进入这个门”。不关心具体操作哪个数据,只关心你有没有这个资格。 +### 场景一:用户 A 创建应用 -- **原理**: 检查用户的角色(Role)是否包含指定权限。 -- **配置**: 通常在路由定义时使用。 +``` +1. 用户A创建应用 "VBase" +2. 自动创建权限: + - PermissionID: "app:vbase" + - Level: 7 (创建者完全控制) +``` -```go -// 只有管理员 (拥有 user:delete 权限) 可以删除用户 -Router.Delete("/{user_id}", auth.VBaseAuth.Perm("user:delete"), DeleteUser) +### 场景二:用户 A 邀请用户 B 加入应用 -// 只有拥有 user:read 权限的人可以查看列表 -Router.Get("/", auth.VBaseAuth.Perm("user:read"), ListUsers) +``` +1. 用户A授予用户B: app:vbase level 2 (读) +2. 用户B权限表: + - app:vbase level 2 +3. 用户B可执行: + - ✓ 读取 vbase 信息 + - ✗ 修改/删除 ``` ---- +### 场景三:用户 B 创建角色 -## 4. 场景二:简单手动鉴权 (Manual Check) +``` +前置: 用户B有 app:vbase level 2 (读),需要额外授权 -对于大多数业务场景(如电商订单、个人博客文章),资源的所有权非常明确且单一。此时,直接在业务代码中判断 `UserID` 字段是最简单、最高效的方式。 +1. 用户A授予用户B: app:vbase:role level 1 (创建角色) +2. 用户B创建角色 "Editor" +3. 自动创建权限: + - PermissionID: "app:vbase:role:editor" + - Level: 7 +``` + +--- -**推荐范式:** +## 五、Auth 接口设计 ```go -// 更新文章 (PATCH /articles/{id}) -func UpdateArticle(x *vigo.X) { - // 1. 获取 ID - articleID := x.PathParams.Get("id") - currentUserID := auth.GetUserID(x) - - // 2. 查库获取资源 - article := db.GetArticle(articleID) - - // 3. 【核心鉴权逻辑】 - // 允许条件:(我是作者) OR (我是管理员/有特权) - if article.OwnerID != currentUserID { - // 如果不是作者,再检查是否有全局权限进行兜底 - if !auth.VBaseAuth.CheckPerm(x.Context(), currentUserID, "", "article:update", "") { - return vigo.ErrForbidden - } - } - - // 4. 执行更新 - db.Save(article) +package auth + +import ( + "context" + "github.com/veypi/vigo" +) + +// ========== 权限等级 ========== + +const ( + LevelNone = 0 + LevelCreate = 1 // 001 创建 (检查奇数层) + LevelRead = 2 // 010 读取 (检查偶数层) + LevelWrite = 4 // 100 写入 (检查偶数层) + LevelReadWrite = 6 // 110 读写 (检查偶数层) + LevelAdmin = 7 // 111 管理员 (完全控制) +) + +// PermFunc 权限检查函数类型 +type PermFunc func(x *vigo.X) error + +// Auth 权限管理接口 +type Auth interface { + // ========== 上下文 ========== + + // UserID 获取当前用户ID + UserID(x *vigo.X) string + + // ========== 登录检查 ========== + + // Login 检查用户是否登录 + Login() PermFunc + + // ========== 权限检查 ========== + + // Perm 检查权限 + // code: 权限码,支持动态解析 + // - 固定写法: "app:vbase" + // - 动态解析: "app:{appID}" 从 path 获取 + // "app:{appID@query}" 从 query 获取 + // "app:{appID@header}" 从 header 获取 + // "app:{appID@ctx}" 从 ctx 获取 + // level: 需要的权限等级 + Perm(code string, level int) PermFunc + + // ========== 快捷方法 ========== + + // PermCreate 检查创建权限 (level 1,检查奇数层) + PermCreate(code string) PermFunc + + // PermRead 检查读取权限 (level 2,检查偶数层) + PermRead(code string) PermFunc + + // PermWrite 检查更新权限 (level 4,检查偶数层) + PermWrite(code string) PermFunc + + // PermAdmin 检查管理员权限 (level 7,检查偶数层) + PermAdmin(code string) PermFunc + + // ========== 权限授予(业务调用) ========== + + // Grant 授予权限 + // 在创建资源、被授权等业务逻辑中调用 + // permissionID: 权限码,如 "app:vbase" + // level: 权限等级 + Grant(ctx context.Context, userID, permissionID string, level int) error + + // Revoke 撤销权限 + Revoke(ctx context.Context, userID, permissionID string) error + + // ========== 权限查询 ========== + + // Check 检查权限 不支持动态解析 + // permissionID: 完整的权限码,如 "app:vbase" + Check(ctx context.Context, userID, permissionID string, level int) bool + + // ========== 资源列表查询 ========== + + // ListResources 查询用户在特定资源类型下的详细权限信息 + // 用于解决 "查询我有权限的 app 列表" 等场景 + // userID: 用户ID + // resourceType: 资源类型 (奇数层),如 "app" 或 "app:{appID}:role" + // 返回: map[实例ID]权限等级 (如 {"vbase": 2, "other": 7}) + ListResources(ctx context.Context, userID, resourceType string) (map[string]int, error) + + // ListUsers 查询特定资源的所有协作者及其权限 + // 用于解决 "查看这个应用有哪些成员" 等场景 + // permissionID: 资源实例权限码,如 "app:vbase" + // 返回: map[用户ID]权限等级 (如 {"user1": 2, "user2": 7}) + ListUsers(ctx context.Context, permissionID string) (map[string]int, error) } -``` -**优点**: -- **零开销**: 不需要额外的 ACL 表查询。 -- **逻辑清晰**: 鉴权逻辑与业务逻辑紧密结合,不易出错。 +// ========== 数据结构 ========== + +// Permission 用户权限 +type Permission struct { + ID string `json:"id"` + UserID string `json:"user_id"` + RoleID string `json:"role_id"` + PermissionID string `json:"permission_id"` + Level int `json:"level"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} +``` --- -## 5. 场景三:复杂资源鉴权 (PermOnResource 中间件) +## 六、使用示例 -对于像“项目协作”、“共享文档”这样需要多人协作、权限动态分配的资源,简单的字段判断就不够用了。这时我们需要引入 ACL (Access Control List)。 +### 6.1 固定写法 -### 5.1 使用方法 +```go +var Router = vigo.NewRouter() -**路由配置**: -告诉中间件去检查 `user_permissions` 表,看当前用户对这个 `project_id` 是否有 `project:update` 权限。 +func init() { + // 创建应用 - 需要系统级 app 权限 + Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp) -```go -// 这里的 "project_id" 是 URL 路径参数的 key -Router.Patch("/{project_id}", auth.VBaseAuth.PermOnResource("project:update", "project_id"), UpdateProject) + // 超级管理员接口 + Router.Get("/admin/users", cfg.Auth.PermAdmin("*"), AdminListUsers) +} ``` -### 5.2 授权 (Grant) +### 6.2 动态解析 -在创建资源时,必须**显式**授予创建者权限。 +```go +func init() { + // 从路径参数获取 appID (默认) + // GET /apps/{appID} + Router.Get("/apps/{appID}", cfg.Auth.PermRead("app:{appID}"), GetApp) + + // 从 query 参数获取 + // GET /apps?appID=xxx + Router.Get("/apps", cfg.Auth.PermRead("app:{appID@query}"), GetApp) + + // 多层嵌套 + // GET /apps/{appID}/roles/{roleID} + Router.Get("/apps/{appID}/roles/{roleID}", + cfg.Auth.PermRead("app:{appID}:role:{roleID}"), + GetRole, + ) +} +``` + +### 6.3 完整示例 ```go -func CreateProject(x *vigo.X) { - // ... 创建项目逻辑 ... - project := db.CreateProject(...) +var Router = vigo.NewRouter().Use(cfg.Auth.Login()) + +func init() { + // 创建应用 - 系统级权限 + Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp) - // 【关键】赋予创建者对该资源的全部权限 - // 权限ID "project:*" 表示对该项目的所有操作权限 - auth.VBaseAuth.GrantResourcePerm(x.Context(), currentUserID, orgID, "project:*", project.ID) + // 列出我的应用 - 只需登录 + Router.Get("/apps", ListMyApps) + + // 应用操作 - 从路径获取 + Router.Get("/apps/{appID}", cfg.Auth.PermRead("app:{appID}"), GetApp) + Router.Put("/apps/{appID}", cfg.Auth.PermWrite("app:{appID}"), UpdateApp) + Router.Delete("/apps/{appID}", cfg.Auth.PermAdmin("app:{appID}"), DeleteApp) + + // 角色操作 - 嵌套资源 + Router.Post("/apps/{appID}/roles", cfg.Auth.PermCreate("app:{appID}:role"), CreateRole) + Router.Get("/apps/{appID}/roles/{roleID}", cfg.Auth.PermRead("app:{appID}:role:{roleID}"), GetRole) + Router.Put("/apps/{appID}/roles/{roleID}", cfg.Auth.PermWrite("app:{appID}:role:{roleID}"), UpdateRole) + Router.Delete("/apps/{appID}/roles/{roleID}", cfg.Auth.PermAdmin("app:{appID}:role:{roleID}"), DeleteRole) } ``` +### 6.4 动态解析规则 + +| 语法 | 来源 | 示例 | +|------|------|------| +| `{key}` | path 参数 | `{appID}` | +| `{key@query}` | query 参数 | `{appID@query}` | +| `{key@header}` | header | `{appID@header}` | +| `{key@ctx}` | context | `{appID@ctx}` | + --- -## 6. 设计决策记录 (ADR) +## 七、接口说明 -### 6.1 废弃隐式所有权推断 (PermWithOwner) -我们移除了曾尝试自动推断资源所有权的 `PermWithOwner` 中间件。因为在中间件层无法准确知道资源的 `OwnerID` 字段名,也无法处理复杂的“多所有者”场景,这导致了安全漏洞和难以调试的错误。现在我们推荐使用 **Manual Check** 模式。 +### 7.1 业务调用 vs 管理端 -### 6.2 上下文精简 -为了减少内存占用和数据库压力,Request Context (`vigo.X`) 中现在**仅**包含最核心的 `UserID`。其他的非核心信息(如组织信息、详细的用户资料)都改为**按需加载**(On-Demand)或通过特定中间件(如 `LoadOrg`)加载。 +此接口是**业务层**调用,用于: +- 创建资源时自动授予权限 +- 业务逻辑中检查权限 + +**管理端**(如权限管理后台)可以通过直接操作数据库实现批量管理。 + +### 7.2 Grant 调用时机 + +```go +// 创建应用时 +func CreateApp(x *vigo.X, req *CreateAppReq) (*AppResp, error) { + app := models.App{Name: req.Name} + db.Create(&app) + + // 授予创建者完全控制权限 + cfg.Auth.Grant(x.Context(), userID, "app:"+app.ID, auth.LevelAdmin) + + return &AppResp{App: app}, nil +} +``` -### 6.3 组织信息解耦 -组织信息的获取逻辑已从核心 `AuthMiddleware` 中剥离,移至 `LoadOrg` 中间件。这意味着不涉及组织业务的接口(如个人资料、系统设置)不再承担加载组织信息的额外开销。 +### 7.3 列表与搜索接口设计 + +对于资源列表(List)或搜索接口,推荐以下设计模式: + +1. **全量管理接口**(如后台管理系统): + - 使用 `PermAdmin("*")` 或 `PermAdmin("app:*")`。 + - 这类接口返回所有数据,必须严格控制权限。 + +2. **用户侧列表/搜索**(如“我的应用”): + - **方式一(仅所有者)**: + - 使用 `Login()` 确保登录。 + - 业务层:`db.Where("owner_id = ?", userID).Find(&apps)` + - **方式二(协作模式 - 使用 ListResources)**: + - 调用 Auth 接口获取有权限的 ID 列表。 + - `perms, _ := auth.ListResources(ctx, userID, "app")` + - `ids := keys(perms)` + - 业务层:`db.Where("id IN ?", ids).Find(&apps)` + - **方式三(混合模式)**: + - 同时查询 owner_id 和 授权列表。 + - `perms, _ := auth.ListResources(...)` + - `ids := keys(perms)` + - `db.Where("owner_id = ? OR id IN ?", userID, ids).Find(&apps)` diff --git a/docs/configuration.md b/docs/configuration.md index a3773e8..dcf9868 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -98,300 +98,3 @@ init_admin: **其他注意事项:** - 仅在没有用户时生效,已有用户则跳过 -- 密码会被 bcrypt 加密存储 -- 自动授予 `admin` 角色(系统级权限) -- 启动成功后会打印日志:`[vbase] Initial admin user 'xxx' created successfully` - -### 1.3 使用场景 - -- 多环境部署(开发/测试/生产使用不同的数据库) -- 容器化部署(通过环境变量注入) -- 密钥管理(密钥文件不进入版本控制) - -### 1.4 注意事项 - -- 修改后需要**重启服务**才能生效 -- 敏感信息(密码、密钥)建议通过环境变量注入 -- 生产环境务必修改默认密钥 - ---- - -## 二、线上配置(Runtime Config) - -存储在数据库 `settings` 表,支持运行时动态修改,无需重启服务。 - -### 2.1 配置分类 - -| 分类 | 前缀 | 说明 | -|------|------|------| -| `auth` | `auth.*` | 登录注册策略 | -| `email` | `email.*` | 邮件服务配置 | -| `sms` | `sms.*` | 短信服务配置 | -| `security` | `security.*` | 安全策略 | -| `oauth` | `oauth.*` | 第三方登录配置 | - -### 2.2 认证配置(auth) - -| 配置键 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `auth.reg.require_email` | bool | `false` | 注册是否要求填写邮箱 | -| `auth.reg.require_phone` | bool | `false` | 注册是否要求填写手机号 | -| `auth.login.methods` | json | `["password"]` | 启用的登录方式:`password`/`email_code`/`phone_code` | -| `auth.login.password_fields` | json | `["username"]` | 密码登录支持的身份标识 | - -**配置组合示例:** - -```json -// 仅用户名登录(最小化配置) -{ - "auth.reg.require_email": "false", - "auth.reg.require_phone": "false", - "auth.login.methods": "[\"password\"]", - "auth.login.password_fields": "[\"username\"]" -} - -// 用户名+邮箱,支持邮箱验证码登录 -{ - "auth.reg.require_email": "true", - "auth.reg.require_phone": "false", - "auth.login.methods": "[\"password\", \"email_code\"]", - "auth.login.password_fields": "[\"username\", \"email\"]" -} - -// 用户名+手机,支持手机验证码登录 -{ - "auth.reg.require_email": "false", - "auth.reg.require_phone": "true", - "auth.login.methods": "[\"password\", \"phone_code\"]", - "auth.login.password_fields": "[\"username\", \"phone\"]" -} -``` - -### 2.3 验证码配置(security) - -| 配置键 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `code.expiry` | int | `5` | 验证码有效期(分钟) | -| `code.length` | int | `6` | 验证码长度 | -| `code.max_attempt` | int | `3` | 最大验证尝试次数 | -| `code.send_interval` | int | `60` | 发送间隔(秒) | -| `code.max_daily_count` | int | `100` | 单日最大发送次数(0=禁用,-1=不限制) | - -### 2.4 邮件配置(email) - -| 配置键 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `email.enabled` | bool | `false` | 是否启用邮件服务 | -| `email.provider` | string | `"smtp"` | 邮件服务商:smtp/sendgrid | -| `email.smtp.host` | string | `""` | SMTP 服务器地址 | -| `email.smtp.port` | int | `587` | SMTP 端口 | -| `email.smtp.user` | string | `""` | SMTP 用户名 | -| `email.smtp.pass` | string | `""` | SMTP 密码(加密存储) | -| `email.from` | string | `""` | 发件人地址 | -| `email.from_name` | string | `"VBase"` | 发件人显示名称 | - -**SMTP 配置示例:** - -```json -{ - "email.enabled": "true", - "email.provider": "smtp", - "email.smtp.host": "smtp.gmail.com", - "email.smtp.port": "587", - "email.smtp.user": "noreply@example.com", - "email.smtp.pass": "encrypted_password", - "email.from": "noreply@example.com", - "email.from_name": "MyApp" -} -``` - -### 2.5 短信配置(sms) - -| 配置键 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `sms.enabled` | bool | `false` | 是否启用短信服务 | -| `sms.provider` | string | `"aliyun"` | 短信服务商:aliyun/tencent | -| `sms.access_key` | string | `""` | 阿里云 AccessKey ID | -| `sms.access_secret` | string | `""` | 阿里云 AccessKey Secret(加密存储) | -| `sms.sign_name` | string | `""` | 短信签名 | -| `sms.template_code` | string | `""` | 验证码模板 CODE | -| `sms.endpoint` | string | `""` | 自定义接入点(可选) | - -### 2.6 第三方登录(OAuth Providers) - -OAuth Provider 配置存储在数据库中,支持动态添加、修改、启用/禁用。系统内置常用 Provider 模板,也可自定义接入任意支持 OAuth 2.0 的平台。 - -**内置模板:** - -| 模板名称 | 说明 | -|----------|------| -| `google` | Google 账号登录 | -| `github` | GitHub 账号登录 | -| `wechat` | 微信登录 | -| `feishu` | 飞书登录 | -| `dingtalk` | 钉钉登录 | - -**Provider 数据结构:** - -| 字段 | 类型 | 说明 | -|------|------|------| -| `code` | string | 唯一标识,如 `google`、`github` | -| `name` | string | 显示名称 | -| `enabled` | bool | 是否启用 | -| `client_id` | string | OAuth Client ID | -| `client_secret` | string | OAuth Client Secret | -| `auth_url` | string | 授权端点 URL | -| `token_url` | string | Token 交换端点 URL | -| `user_info_url` | string | 用户信息端点 URL | -| `scopes` | []string | 请求的权限范围 | -| `user_id_path` | string | 从用户信息中提取 ID 的字段路径 | -| `user_name_path` | string | 从用户信息中提取用户名的字段路径 | -| `user_email_path` | string | 从用户信息中提取邮箱的字段路径 | -| `user_avatar_path` | string | 从用户信息中提取头像的字段路径 | -| `extra_config` | json | 额外配置参数 | - -**Field Path 说明:** - -用于从 OAuth 服务商返回的用户信息 JSON 中提取字段,支持点号路径: - -- `id` - 直接取根级 id 字段 -- `data.employee_id` - 取 data 对象下的 employee_id -- `sub` - OpenID Connect 标准字段 - -**使用内置模板创建 Provider:** - -```http -POST /api/v1/oauth/providers - -{ - "template": "google", - "name": "Google", - "client_id": "your-client-id.apps.googleusercontent.com", - "client_secret": "your-client-secret", - "enabled": true -} -``` - -**自定义 Provider 示例(企业微信):** - -```http -POST /api/v1/oauth/providers - -{ - "code": "wecom", - "name": "企业微信", - "client_id": "wwxxxxxxxxxxxxxxxx", - "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "auth_url": "https://open.weixin.qq.com/connect/oauth2/authorize", - "token_url": "https://qyapi.weixin.qq.com/cgi-bin/gettoken", - "user_info_url": "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo", - "scopes": ["snsapi_base"], - "user_id_path": "UserId", - "user_name_path": "name", - "extra_config": { - "agent_id": "1000002" - } -} -``` - ---- - -## 三、配置管理 API - -### 3.1 获取配置 - -```http -# 获取所有配置 -GET /api/v1/settings - -# 获取指定分类 -GET /api/v1/settings?category=auth - -# 响应示例 -{ - "data": [ - { - "key": "auth.reg.require_email", - "value": "false", - "type": "bool", - "category": "auth", - "desc": "注册是否要求邮箱" - } - ] -} -``` - -### 3.2 更新配置 - -```http -# 批量更新(管理员权限) -PATCH /api/v1/settings - -{ - "settings": [ - {"key": "auth.reg.require_email", "value": "true"}, - {"key": "auth.login.methods", "value": "[\"password\", \"email_code\"]"} - ] -} - -# 响应 -{ - "message": "配置已更新", - "updated": 2 -} -``` - ---- - -## 四、配置优先级 - -当配置存在冲突时,优先级从高到低: - -1. **环境变量** - 如 `VBASE_DSN`、`VBASE_PORT` -2. **配置文件** - `config.yaml` -3. **代码默认值** - `cfg/cfg.go` 中的默认值 -4. **运行时配置** - 数据库 `settings` 表(仅适用于线上配置项) - ---- - -## 五、部署建议 - -### 5.1 开发环境 - -```yaml -# config.yaml -db: "sqlite" -dsn: "file:./dev.db?cache=shared" -redis: - addr: "memory" -``` - -### 5.2 生产环境 - -```yaml -# config.yaml(最小化) -dsn: ${DB_DSN} -redis: - addr: ${REDIS_ADDR} - password: ${REDIS_PASSWORD} -key: ${SECRET_KEY} # 32位以上随机字符串 -storage_path: /data/storage -``` - -线上配置通过管理后台设置: - -1. 首次启动后访问 `http://host:port/admin` -2. 使用初始管理员账号登录 -3. 进入「系统设置」配置邮件/短信/登录策略 - ---- - -## 六、变更日志 - -| 版本 | 变更内容 | -|------|---------| -| v1.0 | 分离本地配置和线上配置 | -| v1.0 | 统一验证码模块(支持邮箱+短信) | -| v1.0 | 支持动态修改登录注册策略 | -| v1.0 | 支持动态 OAuth Provider(内置模板+自定义接入) | -| v1.0 | 统一登录方式配置(密码/邮箱验证码/手机验证码/OAuth) | diff --git a/docs/design.md b/docs/design.md index a2f1449..562468d 100644 --- a/docs/design.md +++ b/docs/design.md @@ -2,7 +2,7 @@ ## 1. 概览 -VBase 是一个基于 Golang 的高性能后端基础框架,旨在提供一套标准化的用户管理、组织架构(多租户)、权限控制(RBAC)和 OAuth2 认证服务。项目采用分层架构设计,基于 `vigo` 框架构建,强调代码的可维护性、扩展性和安全性。 +VBase 是一个基于 Golang 的高性能后端基础框架,旨在提供一套标准化的用户管理、作用域权限控制(Scoped RBAC)和 OAuth2 认证服务。项目采用分层架构设计,基于 `vigo` 框架构建,强调代码的可维护性、扩展性和安全性。 ## 2. 技术栈 @@ -30,46 +30,49 @@ Response <- [Global After Middleware] <------------------------------------+ ├── api/ # API 接口层 (路由定义、请求处理) │ ├── auth/ # 认证相关接口 (登录、注册、刷新Token) │ ├── oauth/ # OAuth2 Provider 接口 -│ ├── org/ # 组织/租户管理接口 +│ ├── role/ # 角色管理接口 │ ├── user/ # 用户管理接口 │ └── init.go # 路由聚合与全局中间件配置 -├── auth/ # 核心权限控制模块 (RBAC 实现) +├── auth/ # 核心权限控制模块 (Scoped RBAC 实现) ├── cfg/ # 配置与基础设施 (DB, Redis, Log) ├── models/ # 数据模型定义 (GORM 结构体) ├── libs/ # 通用工具库 ├── cli/ # 命令行入口 -└── doc/ # 文档 +└── docs/ # 文档 ``` ## 4. 核心模块设计 ### 4.1 认证与授权 (Auth Module) -Auth 模块是系统的核心安全组件,实现了基于角色的访问控制 (RBAC) 和资源级权限管理。 +Auth 模块是系统的核心安全组件,实现了基于作用域(Scope)的角色访问控制 (RBAC) 和资源级权限管理。 #### 4.1.1 核心概念 -- **Permission (权限)**: 最小粒度的操作许可,格式严格遵循 `resource:action` 或 `app:resource:action`。 - - 示例: `user:read`, `org:create`, `oauth-client:delete` - - **约束**: 资源标识符 (`resource`) 只能包含字母、数字、下划线和连字符,**严禁包含冒号**,以避免解析歧义。 -- **Role (角色)**: 权限的集合。系统预设角色包括 `admin` (管理员) 和 `user` (普通用户)。 -- **UserRole (用户-角色关联)**: 用户在特定组织 (`OrgID`) 下拥有的角色。 -- **Policy (策略)**: 定义角色拥有的权限列表。 +- **Scope (作用域)**: 权限隔离的边界,不同应用或模块可以拥有独立的权限体系(如 "vb", "app1")。 +- **Permission (权限)**: 最小粒度的操作许可,格式为树状结构字符串。 + - **层级定义**: + - **奇数层**: 资源类型 (Level 1: Create) + - **偶数层**: 资源实例 (Level 2: Read, Level 4: Write, Level 7: Admin) + - 示例: `org:orgA:project:projB` +- **Role (角色)**: 权限的集合。角色也属于特定 Scope。 +- **UserRole (用户-角色关联)**: 用户在特定 Scope 下拥有的角色。 #### 4.1.2 权限验证机制 -系统提供 `auth.Auth` 接口和 `VBaseAuth` 实例,支持多种验证方式: +系统提供 `auth.Auth` 接口和 `auth.Factory` 工厂,支持多应用集成: -1. **基础权限**: `Perm("resource:action")` - 检查用户是否拥有指定权限。 -2. **资源所有者**: `PermWithOwner("resource:action", "owner_id_key")` - 如果用户是资源所有者则放行,否则检查权限。 -3. **特定资源**: `PermOnResource("resource:action", "resource_id_key")` - 检查用户对特定资源实例的权限。 -4. **组合权限**: `PermAny`, `PermAll` - 支持“任一”或“所有”权限的逻辑组合。 -5. **通配符支持**: 支持 `*` 通配符,如 `app:resource:*` 匹配该资源下的所有操作。 +1. **获取实例**: `myAuth := auth.Factory.New("my_scope")` +2. **基础权限**: `myAuth.PermRead("resource:id")` - 检查读取权限。 +3. **层级检查**: + - **Admin (Level 7)**: 拥有 `*` 或前缀匹配权限(向下继承)。 + - **Standard**: 精确匹配且满足 Level 要求。 +4. **动态解析**: 支持从 URL、Query、Header 解析 ID,如 `org:{orgID}`。 #### 4.1.3 中间件流程 -1. **AuthMiddleware**: 解析 JWT Token,提取 UserID 和 OrgID,注入到请求上下文 (`vigo.X`)。 -2. **PermMiddleware**: 在业务 Handler 执行前拦截请求,调用 `CheckPermission` 进行鉴权。 +1. **LoginMiddleware**: 解析 JWT Token,提取 UserID。 +2. **PermMiddleware**: 在业务 Handler 执行前拦截请求,调用 `Check` 进行鉴权。 ### 4.2 用户体系 (User Module) @@ -77,15 +80,7 @@ Auth 模块是系统的核心安全组件,实现了基于角色的访问控制 - **Identity**: 认证信息表,支持多种登录方式 (密码、OAuth、验证码等) 关联到同一用户。 - **Session**: 用户会话管理,用于记录登录状态和刷新 Token。 -### 4.3 组织架构 (Org Module) - -支持多租户模型的组织管理: - -- **Org**: 组织/团队实体。 -- **OrgMember**: 组织成员关系表,记录用户在组织内的角色 (`RoleIDs`)。 -- **Context 隔离**: 所有数据操作通过 `OrgID` 进行逻辑隔离 (在 `auth.AuthMiddleware` 中解析并注入)。 - -### 4.4 OAuth2 服务 (OAuth Module) +### 4.3 OAuth2 服务 (OAuth Module) 实现了完整的 OAuth2 Provider 功能,支持第三方应用接入: @@ -116,7 +111,7 @@ Auth 模块是系统的核心安全组件,实现了基于角色的访问控制 **错误响应**: ```json { - "code": 400, // 或 401, 403, 500 等 + "code": 40001, // 400 + 01 (Bad Request + Invalid Argument) "message": "错误描述信息" } ``` @@ -139,66 +134,6 @@ Auth 模块是系统的核心安全组件,实现了基于角色的访问控制 ## 8. 开发规范 -1. **资源命名**: 权限资源标识符必须使用 `kebab-case` (如 `oauth-client`) 或 `snake_case`,**禁止使用冒号**。 +1. **资源命名**: 权限资源标识符必须使用 `kebab-case` 或 `snake_case`,使用冒号 `:` 分隔层级。 2. **错误处理**: 优先使用 `vigo.NewError` 或预定义错误 (如 `vigo.ErrNotFound`),以便统一处理 HTTP 状态码。 -3. **测试**: 编写集成测试脚本 (`test.sh`, `full_test.sh`) 覆盖核心业务流程。 - -## 9. 实战场景指南 (Use Cases) - -VBase 的 `Org` (组织) 设计非常灵活,既支持单租户应用,也支持复杂的多租户 B2B 系统。以下是几种典型场景的最佳实践。 - -### 场景一:B2C 电商平台 / 简单应用 (Single Tenant) - -**示例**: 网上书店、个人博客、C端工具应用。 -**特点**: 所有用户直接面对平台,不存在“团队”或“公司”的概念。 - -- **Org 使用策略**: - - **忽略 Org**: 绝大多数 API 请求不需要携带 `X-Org-ID`。 - - **权限管理**: 用户角色(如 `admin`, `user`)直接绑定到 Global 域 (`org_id=""`)。 - - **数据隔离**: 数据通常是全局可见(如商品列表)或基于 `UserID` 隔离(如用户订单)。 - -- **权限模型**: - - **管理员**: 拥有全局 `admin` 角色,管理所有书籍 (`book:create`, `book:delete`)。 - - **普通用户**: 拥有全局 `user` 角色,可以浏览和购买 (`book:read`, `order:create`)。 - - **接口调用**: 客户端无需处理 `OrgID`,直接使用 Token 访问。 - -### 场景二:B2B SaaS 系统 (Multi-Tenant) - -**示例**: 项目管理工具 (Jira)、企业协作平台 (Slack)、HR 系统。 -**特点**: 客户以“公司”或“团队”为单位,数据严格隔离。 - -- **Org 使用策略**: - - **强制 Org**: 几乎所有业务 API (如创建任务、查看员工) 都必须在 Header 中携带 `X-Org-ID`。 - - **数据隔离**: 数据库查询必须带上 `Where("org_id = ?", ctxOrgID)`。 - - **角色复用**: 同一个用户 (User) 可以加入多个组织 (Org),在不同组织中拥有不同角色 (在 A 公司是管理员,在 B 公司是普通成员)。 - -- **权限模型**: - - **用户张三**: - - 在 **字节跳动 (OrgA)**: 角色 `admin` -> 权限 `project:create`, `member:add`。 - - 在 **个人工作室 (OrgB)**: 角色 `viewer` -> 权限 `project:read`。 - - **鉴权流程**: `AuthMiddleware` 会自动校验张三是否是目标 Org 的成员,并将对应的角色权限加载到上下文中。 - -### 场景三:双边市场 / 平台型 SaaS (Hybrid) - -**示例**: 淘宝/亚马逊 (平台 + 商家)、外卖平台。 -**特点**: 既有平台运营方,又有独立商家 (Org),还有 C 端消费者。 - -- **Org 使用策略**: - - **商家端 (Seller)**: 类似 B2B 模式。商家登录后,操作店铺数据需携带 `X-Org-ID` (店铺ID)。 - - **消费者端 (Buyer)**: 类似 B2C 模式。消费者浏览商品不需要 Org 上下文,或者处于一个特殊的“公域”上下文中。 - - **平台管理 (Platform Admin)**: 拥有全局超级权限,可以管理所有 Org。 - -- **权限模型**: - - **平台管理员**: 全局 `super_admin`,可封禁任何商家 (`org:delete`)。 - - **商家**: 在自己的 Org 内拥有 `shop_admin`,管理自家商品 (`product:create`)。 - - **消费者**: 全局 `buyer`,可跨 Org 下单 (`order:create`)。 - -### 总结 - -| 场景 | Org 角色 | 权限绑定 | 请求 Header | 数据隔离方式 | -| :--- | :--- | :--- | :--- | :--- | -| **B2C (书店)** | 不使用 / 仅后台用 | 全局绑定 (`org_id=""`) | 无需 `X-Org-ID` | 基于 `UserID` 或公开 | -| **B2B (Jira)** | 核心隔离单元 | 绑定到特定 Org | **必须** `X-Org-ID` | 严格基于 `OrgID` | -| **平台 (淘宝)** | 商家店铺 | 商家绑定 Org / 买家全局 | 商家端需要 / 买家端不需要 | 商家数据基于 `OrgID` | - -在 VBase 中,通过 `CheckPermission` 接口的逻辑(优先检查指定 Org 的角色,若无则检查全局角色),可以完美兼容上述所有模式。 +3. **测试**: 编写集成测试脚本覆盖核心业务流程。 diff --git a/docs/integration.md b/docs/integration.md index 9f8c6e6..a843350 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -1,250 +1,130 @@ -# VBase 集成文档 +# VBase 集成指南 -本文档介绍如何将 VBase 集成到您的 Golang (Vigo) 项目中,快速实现用户管理、权限控制和组织架构功能。 +本文档介绍如何将 VBase 作为基础库集成到现有的 Golang 项目中,并使用其权限管理系统。 -## 1. 快速集成 (Quick Start) +## 1. 安装 -集成 VBase 仅需简单几步: - -### 1.1 引入依赖 - -在您的项目中引入 VBase: - -```go -import "github.com/veypi/vbase" +```bash +go get github.com/veypi/vbase ``` -### 1.2 挂载路由 +## 2. 初始化 -在您的项目根路由初始化处,挂载 VBase 路由: - -```go -// 您的项目初始化代码 -func init() { - // 挂载 vbase 路由到 /vbase 路径下 - // 这样 vbase 的 API 将可以通过 /vb/api/auth/login 等访问 - MyRouter.Extend("/vb", vbase.Router) -} -``` - -### 1.3 配置数据库 - -确保您的项目已经配置了 GORM 数据库连接,VBase 将复用该连接。 - -```go -// VBase 会自动读取您的配置,前提是您使用了兼容的配置结构或手动设置 -vbase.Config.SetDB(yourDB) -// 或者直接集成到您的项目配置中,由vigo.Flags 自动加载 -type AppConfig struct { - Vbase any -} -var Config = *AppConfig{ - Vbase: vbase.Config, -} -``` - ---- - -## 2. 详细集成方案 - -### 2.1 路由集成 - -VBase 提供了一个标准的 `vigo.Router` 实例,包含所有用户、组织、权限相关的 API。 +在你的应用入口文件(如 `main.go` 或 `init.go`)中进行初始化。 ```go package main import ( "github.com/veypi/vbase" + "github.com/veypi/vbase/cfg" + "github.com/veypi/vbase/auth" "github.com/veypi/vigo" ) +// 1. 创建你的应用 Router var Router = vigo.NewRouter() +// 2. 创建你的应用 Auth 实例 (指定 Scope) +var AppAuth = auth.Factory.New("my_app") + func init() { - // 1. 挂载 VBase 路由 - // 建议挂载在独立的前缀下,避免路由冲突 + // 3. 挂载 VBase 路由 (提供登录、用户管理等基础接口) Router.Extend("/vb", vbase.Router) -} -``` - -### 2.2 权限系统集成 - -VBase 提供了强大的 RBAC (基于角色的访问控制) 权限系统。 - -#### 2.2.1 初始化应用权限 - -在您的应用中,使用 `vbase.Auth.New` 创建应用专属的权限实例。 - -```go -import "github.com/veypi/vbase" - -// 定义您的应用权限实例 -var AppAuth = vbase.Auth.New("my_app") -func init() { - // 定义应用的默认角色 - AppAuth.AddRole("admin", "管理员", "*:*") // 拥有所有权限 - AppAuth.AddRole("editor", "编辑", - "article:create", - "article:update", - ) + // 4. 配置数据库连接 (如果尚未配置) + // export DSN="root:password@tcp(127.0.0.1:3306)/myapp?charset=utf8&parseTime=True" } -``` - -#### 2.2.2 使用权限中间件 -使用 `vbase.AuthMiddleware` 进行认证,并结合 `AppAuth.Perm` 进行权限检查。 +func main() { + // 5. 初始化数据库迁移 + if err := vbase.Init(); err != nil { + panic(err) + } -```go -func init() { - // 1. 全局认证中间件 (解析 Token, 注入 user_id, org_id) - Router.Use(vbase.AuthMiddleware()) - Router.Get("/info", "获取app信息", vigo.SkipBefore, getInfo) - // 2. 路由权限控制 - // 检查 "article:create" 权限 - Router.Post("/articles", "发布文章", AppAuth.Perm("article:create"), createArticle) - - // 检查资源所有权 (确保用户只能修改自己的文章) - // 检查 "article:update" 权限,且文章的 owner_id 必须等于当前用户 ID - Router.Patch("/articles/{id}", "更新文章", AppAuth.PermWithOwner("article:update", "id"), updateArticle) + // 6. 启动服务 + app := vigo.New("myapp", Router, cfg.Global, nil) + panic(app.Run()) } ``` -### 2.3 配置管理 +## 3. 使用权限系统 + +### 3.1 定义路由权限 -VBase 允许自定义部分配置。 +使用 `AppAuth` 实例的中间件方法来保护你的路由。 ```go -import "github.com/veypi/vbase" +func init() { + // 需要登录 + Router.Use(AppAuth.Login()) -func main() { - // 获取配置单例 - cfg := vbase.Config - - // 启用调试模式 - cfg.Debug = true + // 资源操作示例 + // 假设你的资源是 "article" - // 设置 JWT 密钥 (建议从环境变量读取) - cfg.JwtSecret = "your-secret-key" - - // 自定义短信服务提供商 (可选) - // vbase.Config.SetSmsProvider(...) -} -``` + // 创建文章 (需要 "article" 的创建权限 Level 1) + Router.Post("/articles", AppAuth.PermCreate("article"), CreateArticle) -### 2.4 上下文使用 + // 读取文章 (需要 "article:{id}" 的读取权限 Level 2) + Router.Get("/articles/{id}", AppAuth.PermRead("article:{id}"), GetArticle) -通过 `vbase.AuthMiddleware` 认证后,您可以在 Handler 中通过 `*vigo.X` 获取用户信息。 + // 更新文章 (需要 "article:{id}" 的写入权限 Level 4) + Router.Put("/articles/{id}", AppAuth.PermWrite("article:{id}"), UpdateArticle) -```go -func MyHandler(x *vigo.X) error { - // 获取当前用户 ID - userID := x.Get("user_id").(string) - - // 获取当前组织 ID (如果有) - orgID := x.Get("org_id").(string) - - // ... 业务逻辑 + // 删除文章 (需要 "article:{id}" 的管理员权限 Level 7) + Router.Delete("/articles/{id}", AppAuth.PermAdmin("article:{id}"), DeleteArticle) } ``` -### 2.5 权限管理高级用法 - -`AppAuth` 实例提供了丰富的接口来管理和检查权限。 - -#### 2.5.1 复杂权限检查中间件 - -除了基础的 `Perm` 和 `PermWithOwner`,还支持复合权限检查: - -```go -// 要求同时拥有 user:read 和 order:read 权限 -Router.Get("/stats", "统计数据", AppAuth.PermAll([]string{"user:read", "order:read"}), getStats) - -// 只要拥有 user:read 或 user:admin 其中之一即可 -Router.Get("/users", "用户列表", AppAuth.PermAny([]string{"user:read", "user:admin"}), listUsers) -``` - -#### 2.5.2 代码中动态检查权限 +### 3.2 业务逻辑授权 -有时需要在 Handler 内部根据业务逻辑进行动态鉴权: +在创建资源时,通常需要授予创建者管理权限。 ```go -func someHandler(x *vigo.X) error { - userID := x.Get("user_id").(string) - orgID := x.Get("org_id").(string) - - // 检查是否有 "report:export" 权限 - // 注意:resourceID 为空时检查通用权限,指定 resourceID 时检查特定资源权限 - allowed, err := AppAuth.CheckPermission(x.Context(), userID, orgID, "report:export", "") +func CreateArticle(x *vigo.X, req *ArticleReq) (*Article, error) { + // 1. 获取当前用户 + userID := AppAuth.UserID(x) - if err != nil || !allowed { - return vigo.ErrForbidden + // 2. 创建资源逻辑... + article := &Article{Title: req.Title, AuthorID: userID} + db.Create(article) + + // 3. 授予权限 + // 授予用户对该文章的管理员权限 (Level 7) + // 这样用户后续可以读取、修改、删除该文章 + permissionID := fmt.Sprintf("article:%s", article.ID) + if err := AppAuth.Grant(x.Context(), userID, permissionID, auth.LevelAdmin); err != nil { + // 处理错误 (通常记录日志) + x.Log.Error("Failed to grant permission", "err", err) } - - // ... -} -``` - -#### 2.5.3 授予和撤销角色 -您可以在业务逻辑中动态授予或撤销用户角色。 -**注意**:`orgID` 可以为空字符串,表示授予系统级(全局)角色。 - -```go -// 授予用户 "editor" 角色 (在指定组织下) -err := AppAuth.GrantRole(ctx, targetUserID, orgID, "editor") - -// 撤销角色 -err := AppAuth.RevokeRole(ctx, targetUserID, orgID, "editor") + return article, nil +} ``` -#### 2.5.4 细粒度资源授权 +### 3.3 复杂场景:项目成员管理 -如果角色机制不够灵活,可以直接授予用户对特定资源的权限: +假设你有一个项目管理系统,用户可以被邀请加入项目。 ```go -// 授予用户对 ID 为 "123" 的文章的 "read" 权限 -err := AppAuth.GrantResourcePerm(ctx, targetUserID, orgID, "article:read", "123") - -// 撤销资源权限 -err := AppAuth.RevokeResourcePerm(ctx, targetUserID, orgID, "article:read", "123") +// 邀请成员接口 +func InviteMember(x *vigo.X, req *InviteReq) error { + // 检查当前用户是否有权限邀请 (通常需要管理员权限) + // 这一步由路由中间件 PermAdmin("project:{id}") 保证 + + // 授予被邀请人读取权限 (Level 2) + permID := fmt.Sprintf("project:%s", req.ProjectID) + return AppAuth.Grant(x.Context(), req.TargetUserID, permID, auth.LevelRead) +} ``` -#### 2.5.5 检查资源权限 - -授予了细粒度资源权限后,可以通过以下两种方式进行检查: - -1. **使用中间件 (推荐)** - - `PermOnResource` 中间件会自动从路径参数或查询参数中获取资源ID,并检查用户是否有权访问该特定资源。 - - ```go - // 自动从路径参数 "id" 获取资源ID (如 /articles/123) - // 如果用户拥有 "article:read" 角色权限,或者被单独授予了对 "123" 的 "article:read" 权限,均可通过检查 - Router.Get("/articles/{id}", "获取文章", AppAuth.PermOnResource("article:read", "id"), getArticle) - ``` - -2. **手动检查** - - 在 Handler 中手动调用 `CheckPermission`。 +## 4. 配置说明 - ```go - func getArticle(x *vigo.X) error { - articleID := x.PathParams.Get("id") - userID := x.Get("user_id").(string) - orgID := x.Get("org_id").(string) +VBase 使用 `cfg` 包管理配置,支持环境变量。 - // 检查权限 - allowed, err := AppAuth.CheckPermission(x.Context(), userID, orgID, "article:read", articleID) - if err != nil { - return err - } - if !allowed { - return vigo.ErrForbidden - } - - // ... - } - ``` +- `DB_DSN`: 数据库连接字符串 +- `DB_TYPE`: 数据库类型 (mysql, postgres, sqlite) +- `JWT_SECRET`: JWT 签名密钥 (生产环境务必修改) +- `JWT_ISSUER`: Token 签发者 +更多配置详情请参考 [配置文档](./configuration.md)。 diff --git a/docs/todo.md b/docs/todo.md index f34b59a..f1cd919 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -4,21 +4,19 @@ ### Dashboard Statistics - **Endpoint**: `GET /api/stats/dashboard` -- **Description**: Returns summary statistics for the dashboard (e.g., total users, active orgs, api calls, revenue). +- **Description**: Returns summary statistics for the dashboard (e.g., total users, api calls). - **Reason**: The dashboard needs high-level metrics to display to the user immediately upon login. Currently using mock data in `ui/page/dashboard/index.html`. ## Future Improvements ### UI - Add proper form validation for all inputs. -- Implement pagination for lists (Users, Orgs, OAuth Clients). +- Implement pagination for lists (Users, OAuth Clients). - Add search and filter functionality for lists. - Improve error handling and user feedback messages. - Add loading states for all async operations. ### Features -- Implement Organization editing (currently placeholder). -- Implement Organization member management (add/remove members). - Implement User creation modal (currently placeholder). - Implement User editing (currently placeholder). - Implement detailed OAuth client management (scopes, secrets). diff --git a/docs/ui.md b/docs/ui.md index 2a06826..e085250 100644 --- a/docs/ui.md +++ b/docs/ui.md @@ -23,14 +23,11 @@ │ │ └── register.html │ ├── dashboard/ # 仪表盘 │ │ └── index.html -│ ├── sys/ # 系统管理 (User, Org, OAuth) +│ ├── sys/ # 系统管理 (User, OAuth) │ │ ├── user/ │ │ │ ├── index.html # 用户列表 │ │ │ └── form.html # 用户创建/编辑 -│ │ ├── org/ -│ │ │ ├── index.html # 组织列表 -│ │ │ └── detail.html # 组织详情/设置 -│ │ └── oauth/ +│ │ ├── oauth/ │ │ ├── index.html # 应用列表 │ │ └── form.html # 应用注册 │ ├── user/ # 个人中心 @@ -51,10 +48,9 @@ ### 2.2 Default Layout (`layout/default.html`) - **用途**: 系统核心业务页面。 - **结构**: - - **Sidebar (Left)**: 导航菜单 (Dashboard, User, Org, OAuth, Settings)。支持折叠。 - - **Header (Top)**: 面包屑导航, 组织切换器 (Org Switcher), 用户头像/下拉菜单 (Profile, Logout)。 + - **Sidebar (Left)**: 导航菜单 (Dashboard, User, OAuth, Settings)。支持折叠。 + - **Header (Top)**: 面包屑导航, 用户头像/下拉菜单 (Profile, Logout)。 - **Main Content**: 路由视图插槽 (``)。 -- **特性**: 需集成 `OrgID` 切换逻辑,切换组织时更新全局状态并刷新数据。 ## 3. 核心模块界面规划与权限 @@ -66,21 +62,10 @@ ### 3.2 仪表盘 (Dashboard) - **权限**: 登录用户 (Authenticated) - **概览页 (`/`)**: 展示核心指标。 - - **普通用户**: 仅可见个人或所属项目的数据概览。 - - **管理员**: 可见整个组织或系统的宏观数据。 + - **普通用户**: 可见个人相关数据概览。 + - **管理员**: 可见整个系统的宏观数据。 -### 3.3 组织管理 (Org Module) -- **组织列表 (`/org`)**: - - **权限**: 登录用户 (Authenticated) - - 展示用户加入的所有组织。 - - “创建组织”入口:视系统配置开放给所有用户或仅限特定用户。 -- **组织详情/设置 (`/org/:id`)**: - - **权限**: 组织成员 (Member of Org) - - **基本信息**: 仅 **Org Admin** 可修改名称、Logo。 - - **成员管理**: 仅 **Org Admin** 可邀请、移除成员或修改角色。 - - **只读视图**: 普通成员仅可查看组织信息和成员列表。 - -### 3.4 用户管理 (User Module) +### 3.3 用户管理 (User Module) - **用户列表 (`/sys/user`)**: - **权限**: 系统管理员 (System Admin Only) - 全局用户管理表格,包含搜索、分页、禁用/启用用户功能。 @@ -88,7 +73,7 @@ - **权限**: 登录用户 (Authenticated) - 基本信息修改 (头像, 昵称)、账号安全 (修改密码, 绑定第三方账号)。 -### 3.5 OAuth2 Provider (OAuth Module) +### 3.4 OAuth2 Provider (OAuth Module) - **应用管理 (`/sys/oauth`)**: - **权限**: 登录用户 (Authenticated) - 开发者注册的 OAuth 应用列表。 @@ -98,69 +83,12 @@ ## 4. 组件策略 ### 4.1 基础组件库 -本项目直接使用 **vhtml-ui** 组件库,无需重复封装基础组件。 -- 按钮、输入框、卡片、模态框、表格等均直接使用库组件。 -- 组件文档:`http://localhost:4000/v/README.md` - -### 4.2 业务组件 -- 仅当组件包含特定业务逻辑且多处复用时,封装为自定义组件。 -- 命名规范:使用短前缀(如 `c-` 或直接目录名)。 -- 存放位置: - - 全局复用:`/ui/c/` - - 局部复用:直接存放在调用方同级目录或 `_components` 子目录中。 - -## 5. 路由规划 (`routes.js`) - -```javascript -const routes = [ - // Public - { path: '/login', component: '/page/auth/login.html', layout: 'public', meta: { guest: true } }, - { path: '/register', component: '/page/auth/register.html', layout: 'public', meta: { guest: true } }, - - // Dashboard (Default Layout) - { - path: '/', - layout: 'default', - meta: { auth: true }, // 登录用户均可访问 - component: '/page/dashboard/index.html' - }, - - // Org Management - { path: '/org', component: '/page/sys/org/index.html', layout: 'default', meta: { auth: true } }, - { - path: '/org/:id', - component: '/page/sys/org/detail.html', - layout: 'default', - meta: { auth: true } // 页面内部需校验是否为成员 - }, - - // User System - { path: '/profile', component: '/page/user/profile.html', layout: 'default', meta: { auth: true } }, - { - path: '/users', - component: '/page/sys/user/index.html', - layout: 'default', - meta: { auth: true, roles: ['admin'] } // 仅系统管理员 - }, - - // OAuth Management - { path: '/oauth/apps', component: '/page/sys/oauth/index.html', layout: 'default', meta: { auth: true } }, - - // Errors - { path: '/403', component: '/page/403.html', layout: 'public' }, - { path: '*', component: '/page/404.html', layout: 'public' } -] -``` - -## 6. 交互与状态管理 - -- **全局状态 (`$env.$G`)**: - - `user`: 当前登录用户信息。 - - `currentOrg`: 当前选中的组织上下文 (影响 Header 显示和 API 请求 Header)。 - - `token`: JWT Token 管理。 -- **API 请求**: - - 使用 `$axios` 拦截器,自动注入 `Authorization: Bearer ...`。 - - 自动注入 `X-Org-ID` (当 `currentOrg` 存在时)。 -- **权限控制**: - - 路由守卫 (`beforeEnter`) 检查登录状态和角色。 - - 页面内使用 `v-if` 或指令控制按钮级别的权限显示。 +使用 `vhtml-ui` 提供的基础组件: +- Button, Input, Select, Checkbox +- Table, Pagination +- Modal, Toast, Confirm +- Card, Badge, Tag + +### 4.2 业务组件 (`ui/c/`) +- ``: 用户选择器 (支持搜索) +- ``: 权限树展示与编辑 diff --git a/scripts/tests/README.md b/scripts/tests/README.md index ccfc490..11835d3 100644 --- a/scripts/tests/README.md +++ b/scripts/tests/README.md @@ -25,9 +25,7 @@ scripts/tests/ ├── run_all.sh # 运行所有测试脚本 (不负责清理环境) ├── 00_none_auth.sh # 1. 未登录访问测试 ├── 01_setup_users.sh # 2. 用户初始化与基础认证 -├── 02_resource_perm.sh # 3. 资源权限交叉测试 -├── 03_org_permission.sh # 4. 组织权限测试 -└── 04_org_load_middleware.sh # 5. LoadOrg 中间件测试 +└── 02_resource_perm.sh # 3. 资源权限交叉测试 ``` ## 推荐运行方式 @@ -63,7 +61,7 @@ bash scripts/tests/02_resource_perm.sh **测试内容**:未登录状态下访问受保护接口 - 验证 API 是否正确拦截未携带 Token 的请求 -- 覆盖 Users, Orgs, Roles, Settings 等核心模块 +- 覆盖 Users, Roles, Settings 等核心模块 ### 01_setup_users.sh @@ -81,23 +79,6 @@ bash scripts/tests/02_resource_perm.sh - 场景 4: User1 修改 Admin 信息 (禁止 403) - 场景 5: User2 修改 User1 信息 (禁止 403) -### 03_org_permission.sh - -**测试内容**:组织权限控制 -- admin 创建组织 -- user 不能修改他人创建的组织 -- admin 邀请 user 加入组织 -- 普通成员不能修改组织信息 -- 只有 admin/owner 可以修改组织 - -### 04_org_load_middleware.sh - -**测试内容**:LoadOrg 中间件验证 -- 验证 `X-Org-ID` 头部的处理 -- 验证用户是否为组织成员的检查逻辑 -- 验证非成员访问组织资源被拒绝 (403) -- 验证成员访问组织资源被允许 (200) - ## 测试环境变量参考 | 变量 | 默认值 | 说明 | diff --git a/tests/README.md b/tests/README.md index f03e983..468a04d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -41,8 +41,6 @@ go test -v ./tests/auth_test.go - **`none_auth_test.go`**: 检查公开端点,并验证受保护端点拒绝未认证请求。 - **`auth_test.go`**: 测试用户生命周期事件(注册 -> 登录 -> 获取/更新个人资料 -> 登出)。 - **`resource_perm_test.go`**: 验证用户除非获得授权(例如管理员),否则无法修改其他用户的数据。 -- **`org_permission_test.go`**: 测试组织基于角色的访问控制 (RBAC)(创建组织 -> 添加成员 -> 验证角色)。 -- **`org_load_middleware_test.go`**: 专门测试 `LoadOrg` 中间件,该中间件强制执行组织特定端点的成员资格检查。 ## 开发注意事项