chore: bump version to v1.2.0 and update all docs

- Bump version from v1.1.1 to v1.2.0
- Add CHANGELOG.md summarizing 20 commits since v1.1.1
- Rewrite docs to match current code: Session auth, Require* APIs,
  nested config (db.dsn/db.type/jwt.*), Cookie-based token delivery
- Update method names uniformly: Perm* -> Require*
- Fix README license badge (Apache -> MIT), port and build commands
- Update auth design docs to reflect Provider + Auth SPI pattern
- Update CLAUDE.md with current architecture and directory structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
master v1.2.0
veypi 4 days ago
parent 3913640f5b
commit 95c1f616be

@ -0,0 +1,34 @@
# Changelog
## v1.2.0 (2026-06-06)
### Features
- **auth**: 替换 user-level token version 为 session-based 认证机制
- **auth**: 支持短信/邮箱验证码注册
- **auth**: 登录时递增 token version 以吊销旧会话
- **auth**: Token 传送方式迁移至 HttpOnly Cookie支持 version-based 吊销
- **api**: 启用 API 文档端点
- **role**: 新增角色用户批量管理 API
- **role**: 支持增量式权限授予和移除
- **cfg**: 新增用户创建钩子user creation hook
- **ui**: 支持 URL 路由中的 `@` 前缀
### Changed
- **cfg**: 默认数据库切换为 SQLite
- **settings**: 用 GORM 结构体查询替换原始 SQL 条件
- **ui**: 简化角色管理界面和认证流程
- **ui**: 用 fetch 替换所有页面中的 axios提取认证布局
- **ui**: 重构 VBase 认证客户端,支持自动刷新和 onAuthSuccess 回调
- **ui**: 前端统一将 `$vbase` 重命名为 `$auth`
### Fixed
- **ui**: 修复用户获取失败时的优雅降级处理
- **ui**: 修复 vhtml script src 使用作用域路径前缀
- **db**: 修复 longtext 字段类型问题
### Removed
- 移除过期的 todo 和 UI 设计文档

@ -9,14 +9,14 @@ VBase is a Go-based identity authentication and permission management framework
- **Language**: Go 1.24+
- **Framework**: Vigo (onion-model middleware)
- **ORM**: GORM (MySQL, PostgreSQL, SQLite supported)
- **Authentication**: JWT + OAuth2
- **Authentication**: Session + JWT (Access/Refresh Token) + Cookie-based delivery + OAuth2
- **Permissions**: Scoped RBAC (Role-Based Access Control)
- **Frontend**: vhtml (embedded HTML-based UI at `/vb/`)
## Common Commands
```bash
# Run development server (default port 4001)
# Run development server (default port 4000)
make run
# Database operations
@ -45,8 +45,10 @@ Response <- [Global After Middleware] <--------+
│ ├── oauth/ # OAuth2 provider endpoints
│ ├── role/ # Role management
│ ├── user/ # User management
│ ├── settings/ # System settings
│ ├── verification/ # SMS/email verification code
│ └── init.go # Router aggregation
├── auth/ # Core Scoped RBAC permission system
├── auth/ # Scoped RBAC permission system + Session management
│ ├── auth.go # Permission checking implementation
│ └── design.md # Permission system design doc
├── cfg/ # Configuration (DB, Redis, JWT settings)
@ -74,8 +76,8 @@ The system uses a scoped permission model where permissions are isolated by `Sco
**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.
- `cfg.Auth.RequireRead(code)`, `cfg.Auth.RequireWrite(code)`: Middleware checks.
- `cfg.Auth.Grant(ctx, userID, permID, level)`: Grant permission.
### API Response Format

@ -2,7 +2,7 @@
<p align="center">
<img src="https://img.shields.io/badge/Go-1.24+-00ADD8?style=flat-square&logo=go" alt="Go Version">
<img src="https://img.shields.io/badge/License-Apache%202.0-blue?style=flat-square" alt="License">
<img src="https://img.shields.io/badge/License-MIT-blue?style=flat-square" alt="License">
<img src="https://img.shields.io/badge/Framework-Vigo-orange?style=flat-square" alt="Framework">
</p>
@ -22,18 +22,19 @@
## 简介
**VBase** 是一个基于 [Vigo](https://github.com/veypi/vigo) 框架开发的高性能后端基础框架提供一套标准化的用户管理、作用域权限控制Scoped RBAC和 OAuth2 认证服务。可作为独立服务部署,也可作为基础库集成到你的 Go 项目中。
**VBase** 是一个基于 [Vigo](https://github.com/veypi/vigo) 框架开发的高性能后端基础框架提供一套标准化的用户管理、作用域权限控制Scoped RBAC和 OAuth2 认证服务。支持 Session + JWT 双 Token 认证、Cookie 令牌传送和短信/邮箱验证码注册。可作为独立服务部署,也可作为基础库集成到你的 Go 项目中。
## 核心特性
- 🔐 **完整认证体系** - JWT Token 认证Access + Refresh、多因素认证短信验证码
- 🛡️ **Scoped RBAC 权限控制** - 基于作用域Scope的角色访问控制支持资源级权限和通配符权限
- <20> **层级权限管理** - 支持资源类型(奇数层)和实例(偶数层)的精细化权限控制
- 🔑 **OAuth2 Provider** - 完整的 OAuth2 服务端实现,支持第三方应用接入
- 🗄️ **多数据库支持** - MySQL、PostgreSQL、SQLite 自动适配
- 📱 **内置管理界面** - 基于 vhtml 的嵌入式管理后台
- 🚀 **高性能** - 基于洋葱模型中间件架构,低延迟高并发
- 🧪 **完整测试** - 集成测试脚本覆盖核心业务流程
- **完整认证体系** — Session + JWTAccess + Refresh TokenHttpOnly Cookie / Header / Query 多通道传送
- **Scoped RBAC 权限控制** — 基于作用域Scope的角色访问控制支持多应用权限隔离
- **层级权限管理** — 支持资源类型(奇数层)和实例(偶数层)的精细化权限控制
- **OAuth2 Provider** — 完整的 OAuth2 服务端实现,支持第三方应用接入
- **多因素认证** — 短信/邮箱验证码注册和验证
- **多数据库支持** — SQLite默认、MySQL、PostgreSQL 自动适配
- **嵌入式管理界面** — 基于 vhtml 的管理后台,开箱即用
- **API 文档** — 内置 `/_api.json` 接口文档端点
- **高性能** — 基于洋葱模型中间件架构Redis 缓存 Session 验证
## 快速开始
@ -50,18 +51,14 @@ go get github.com/veypi/vbase
git clone https://github.com/veypi/vbase.git
cd vbase
# 配置数据库(编辑 dev.yaml 或使用环境变量)
export DSN="root:password@tcp(127.0.0.1:3306)/vbase?charset=utf8&parseTime=True"
export DB="mysql"
# 直接启动(默认 SQLite + 端口 4000
go run ./cli/*.go -p 4000
# 启动服务
go run ./cli/main.go
# 或使用 Makefile默认端口 4001
# 或使用 Makefile
make run
```
服务默认在 `http://localhost:4000` 启动,管理界面访问 `/vb/` 路径。
服务默认在 `http://localhost:4000` 启动,管理界面访问 `/vb/` 路径API 文档访问 `/_api.json`
### 作为库集成
@ -70,14 +67,13 @@ package main
import (
"github.com/veypi/vbase"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vigo"
)
var Router = vigo.NewRouter()
func init() {
// 挂载 VBase 路由到 /vb 前缀
Router.Extend("/vb", vbase.Router)
func main() {
app := vigo.New("myapp", vbase.Router, cfg.Global, vigo.WithInit(vbase.Init))
panic(app.Run())
}
```
@ -91,8 +87,10 @@ vbase/
│ ├── auth/ # 认证接口登录、注册、Token 刷新)
│ ├── oauth/ # OAuth2 Provider 接口
│ ├── role/ # 角色管理
│ └── user/ # 用户管理
├── auth/ # 核心权限控制模块Scoped RBAC 实现)
│ ├── user/ # 用户管理
│ ├── settings/ # 系统设置接口
│ └── verification/ # 验证码接口
├── auth/ # 核心权限控制模块Scoped RBAC + Session 管理)
├── cfg/ # 配置管理
├── cli/ # 命令行入口
├── models/ # 数据模型GORM

@ -2,35 +2,47 @@
## 注意
如果开发中发现什么开发规则或者技巧,你可以更新在这个文档,供其他人看
如果下面某些端口或者路径访问失败,请询问用户是否启动应用
如果开发中发现什么开发规则或者技巧,你可以更新在这个文档,供其他人看
如果下面某些端口或者路径访问失败,请询问用户是否启动应用
## 后端开发
### 运行
```bash
# 使用 SQLite 数据库(默认)
go run ./cli/*.go -p 4000
# 或指定配置文件
go run ./cli/*.go -f ./cfg/dev.yml -l debug -p 4000
```
### 测试
```bash
//重置数据库
# 重置数据库
rm /tmp/vb.sqlite
go run cli/main.go -db.type=sqlite -db.dsn /tmp/vb.sqlite -p 4000
go run ./cli/*.go -p 4000
```
可以通过 <http://localhost:4000/\_api.json> 查看接口列表
可以通过 `http://localhost:4000/_api.json` 查看接口列表。
## UI 界面开发指南
- 界面采用 vhtml 框架,该框架可以将一个 html 文件自动加载为一个组件
- 开始写界面前请阅读全局样式文件 /ui/assets/common.css组件内必须使用全局中的变量去组合或者直接使用全局中的样式 保证所有界面的样式一致, 比如只能使用颜色变量或者通过 color-mix 函数去包含至少一个颜色变量
- 组件内部避免重复的样式定义 如 body 内无需重复定义字体
- 本项目使用 vhtml-ui 组件库,该组件库可以通过 curl -sS <http://localhost:4000/v/README.md> 查看文档 其组件代码都已经映射到了/v/目录下
- 前端路由文件 /ui/routes.js 该文件定义了所有的路由规则
- 开始写界面前请阅读全局样式文件 `/ui/assets/common.css`,组件内必须使用全局中的变量去组合或者直接使用全局中的样式,保证所有界面的样式一致,比如只能使用颜色变量或者通过 color-mix 函数去包含至少一个颜色变量
- 组件内部避免重复的样式定义如 body 内无需重复定义字体
- 本项目使用 vhtml-ui 组件库,该组件库可以通过 `curl -sS http://localhost:4000/v/README.md` 查看文档,其组件代码都已映射到了 `/v/` 目录下
- 前端路由文件 `/ui/routes.js`该文件定义了所有的路由规则
## vhtml-ui 文档查看方法
curl 指令可以不用沙盒运行
获取文档目录 该操作可以查看所有组件的目录结构
curl -sS <http://localhost:4000/v/docs/README.md?toc=1>
获取文档全文(较长,一般建议查询目录再查询章节内容)
curl -sS <http://localhost:4000/v/docs/README.md>
获取章节内容(可以根据第一步获取的目录编号查询内容) 一般使用这个查询章节内容,查询内容时不能带 toc 参数
curl -sS <http://localhost:4000/v/docs/README.md?from=1.2&to=1.2>
获取文档目录(查看所有组件的目录结构):
```bash
curl -sS http://localhost:4000/v/docs/README.md?toc=1
```
获取章节内容(根据目录编号查询内容,不能带 toc 参数):
```bash
curl -sS http://localhost:4000/v/docs/README.md?from=1.2&to=1.2
```

@ -110,16 +110,56 @@ app:vbase:role:admin → 第4层 (偶数) - 实例
## 五、Auth 接口设计
VBase 的权限系统基于 vigo 框架的 `auth` SPI 模式,分为两层:
- **Provider 接口**:由 VBase 实现 `vbaseProvider`,负责实际的权限存储和校验逻辑。
- **Auth 结构体**:由 vigo 框架提供 (`auth.Auth`),包装 Provider提供中间件和高层 API用于业务模块直接调用。
### 5.1 Provider 接口VBase 实现)
```go
package auth
// Provider 是实现端需要实现的 SPI
type Provider interface {
UserID(x *vigo.X) string
Check(ctx context.Context, userID, permCode string, permLevel int) bool
Grant(ctx context.Context, userID, permCode string, permLevel int) error
Revoke(ctx context.Context, userID, permCode string) error
ListResources(ctx context.Context, userID, resourceType string) (map[string]int, error)
ListUsers(ctx context.Context, permCode string) (map[string]int, error)
GrantRole(ctx context.Context, userID, roleCode string) error
RevokeRole(ctx context.Context, userID, roleCode string) error
AddRole(roleCode, roleName string, permPolicies ...string) error
}
```
import (
"context"
"github.com/veypi/vigo"
)
VBase 通过 `auth.Factory.New(scope)` 创建作用域隔离的 Provider 实例,实现多应用间权限隔离。
// ========== 权限等级 ==========
### 5.2 Auth 结构体(业务调用)
```go
// cfg.Auth 是全局权限管理实例,由 vigo 框架提供
// 中间件方法:
cfg.Auth.Login() // 检查登录(不检查权限)
cfg.Auth.Require(permExpr, permLevel) // 通用权限检查
cfg.Auth.RequireCreate(permExpr) // 创建权限 (level 1)
cfg.Auth.RequireRead(permExpr) // 读取权限 (level 2)
cfg.Auth.RequireWrite(permExpr) // 写入权限 (level 4)
cfg.Auth.RequireAdmin(permExpr) // 管理员权限 (level 7)
// 业务调用方法:
cfg.Auth.UserID(x) // 获取当前用户 ID
cfg.Auth.Check(ctx, userID, permCode, level) // 静态权限检查
cfg.Auth.Grant(ctx, userID, permCode, level) // 授予权限
cfg.Auth.Revoke(ctx, userID, permCode) // 撤销权限
cfg.Auth.GrantRole(ctx, userID, roleCode) // 授予角色
cfg.Auth.RevokeRole(ctx, userID, roleCode) // 撤销角色
cfg.Auth.ListResources(ctx, userID, resourceType) // 列出资源权限
cfg.Auth.ListUsers(ctx, permCode) // 列出资源协作者
```
### 5.3 权限等级常量
```go
const (
LevelNone = 0
LevelCreate = 1 // 001 创建 (检查奇数层)
@ -128,92 +168,19 @@ const (
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)
}
// ========== 数据结构 ==========
### 5.4 Permission 数据模型
// Permission 用户权限
```go
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"`
Scope string `json:"scope"` // 作用域
UserID *string `json:"user_id"` // 用户ID直接授权
RoleID *string `json:"role_id"` // 角色ID角色授权
PermissionID string `json:"permission_id"` // 权限ID层级结构
Level int `json:"level"` // 权限等级
ExpireAt *time.Time `json:"expire_at"` // 过期时间(可选)
}
```
@ -228,10 +195,10 @@ var Router = vigo.NewRouter()
func init() {
// 创建应用 - 需要系统级 app 权限
Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp)
Router.Post("/apps", cfg.Auth.RequireCreate("app"), CreateApp)
// 超级管理员接口
Router.Get("/admin/users", cfg.Auth.PermAdmin("*"), AdminListUsers)
Router.Get("/admin/users", cfg.Auth.RequireAdmin("*"), AdminListUsers)
}
```
@ -241,16 +208,16 @@ func init() {
func init() {
// 从路径参数获取 appID (默认)
// GET /apps/{appID}
Router.Get("/apps/{appID}", cfg.Auth.PermRead("app:{appID}"), GetApp)
Router.Get("/apps/{appID}", cfg.Auth.RequireRead("app:{appID}"), GetApp)
// 从 query 参数获取
// GET /apps?appID=xxx
Router.Get("/apps", cfg.Auth.PermRead("app:{appID@query}"), GetApp)
Router.Get("/apps", cfg.Auth.RequireRead("app:{appID@query}"), GetApp)
// 多层嵌套
// GET /apps/{appID}/roles/{roleID}
Router.Get("/apps/{appID}/roles/{roleID}",
cfg.Auth.PermRead("app:{appID}:role:{roleID}"),
cfg.Auth.RequireRead("app:{appID}:role:{roleID}"),
GetRole,
)
}
@ -263,21 +230,21 @@ var Router = vigo.NewRouter().Use(cfg.Auth.Login())
func init() {
// 创建应用 - 系统级权限
Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp)
Router.Post("/apps", cfg.Auth.RequireCreate("app"), CreateApp)
// 列出我的应用 - 只需登录
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.Get("/apps/{appID}", cfg.Auth.RequireRead("app:{appID}"), GetApp)
Router.Put("/apps/{appID}", cfg.Auth.RequireWrite("app:{appID}"), UpdateApp)
Router.Delete("/apps/{appID}", cfg.Auth.RequireAdmin("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)
Router.Post("/apps/{appID}/roles", cfg.Auth.RequireCreate("app:{appID}:role"), CreateRole)
Router.Get("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireRead("app:{appID}:role:{roleID}"), GetRole)
Router.Put("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireWrite("app:{appID}:role:{roleID}"), UpdateRole)
Router.Delete("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireAdmin("app:{appID}:role:{roleID}"), DeleteRole)
}
```
@ -322,7 +289,7 @@ func CreateApp(x *vigo.X, req *CreateAppReq) (*AppResp, error) {
对于资源列表List或搜索接口推荐以下设计模式
1. **全量管理接口**(如后台管理系统):
- 使用 `PermAdmin("*")` 或 `PermAdmin("app:*")`。
- 使用 `RequireAdmin("*")` 或 `RequireAdmin("app:*")`。
- 这类接口返回所有数据,必须严格控制权限。
2. **用户侧列表/搜索**(如“我的应用”):

@ -110,16 +110,56 @@ app:vbase:role:admin → 第4层 (偶数) - 实例
## 五、Auth 接口设计
VBase 的权限系统基于 vigo 框架的 SPI 模式,分为两层:
- **Provider 接口**:由 VBase 实现 (`vbaseProvider`),负责实际的权限存储和校验逻辑。
- **Auth 结构体**:由 vigo 框架提供 (`auth.Auth`),包装 Provider提供中间件和高层 API 供业务模块直接使用。
### 5.1 Provider 接口VBase 实现)
```go
package auth
// Provider 是实现端需要实现的 SPI
type Provider interface {
UserID(x *vigo.X) string
Check(ctx context.Context, userID, permCode string, permLevel int) bool
Grant(ctx context.Context, userID, permCode string, permLevel int) error
Revoke(ctx context.Context, userID, permCode string) error
ListResources(ctx context.Context, userID, resourceType string) (map[string]int, error)
ListUsers(ctx context.Context, permCode string) (map[string]int, error)
GrantRole(ctx context.Context, userID, roleCode string) error
RevokeRole(ctx context.Context, userID, roleCode string) error
AddRole(roleCode, roleName string, permPolicies ...string) error
}
```
import (
"context"
"github.com/veypi/vigo"
)
VBase 通过 `auth.Factory.New(scope)` 创建作用域隔离的 Provider 实例。
// ========== 权限等级 ==========
### 5.2 Auth 结构体(业务调用)
```go
// cfg.Auth 是全局权限管理实例
// 中间件方法:
cfg.Auth.Login()
cfg.Auth.Require(permExpr, permLevel) // 通用权限检查
cfg.Auth.RequireCreate(permExpr) // 创建 (level 1)
cfg.Auth.RequireRead(permExpr) // 读取 (level 2)
cfg.Auth.RequireWrite(permExpr) // 写入 (level 4)
cfg.Auth.RequireAdmin(permExpr) // 管理员 (level 7)
// 业务调用方法:
cfg.Auth.UserID(x) // 获取当前用户 ID
cfg.Auth.Check(ctx, userID, permCode, level) // 静态权限检查
cfg.Auth.Grant(ctx, userID, permCode, level) // 授予权限
cfg.Auth.Revoke(ctx, userID, permCode) // 撤销权限
cfg.Auth.GrantRole(ctx, userID, roleCode) // 授予角色
cfg.Auth.RevokeRole(ctx, userID, roleCode) // 撤销角色
cfg.Auth.ListResources(ctx, userID, resourceType) // 列出资源权限
cfg.Auth.ListUsers(ctx, permCode) // 列出资源协作者
```
### 5.3 权限等级常量
```go
const (
LevelNone = 0
LevelCreate = 1 // 001 创建 (检查奇数层)
@ -128,92 +168,19 @@ const (
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)
}
// ========== 数据结构 ==========
### 5.4 Permission 数据模型
// Permission 用户权限
```go
type Permission struct {
ID string `json:"id"`
UserID string `json:"user_id"`
RoleID string `json:"role_id"`
Scope string `json:"scope"`
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"`
ExpireAt *time.Time `json:"expire_at"`
}
```
@ -228,10 +195,10 @@ var Router = vigo.NewRouter()
func init() {
// 创建应用 - 需要系统级 app 权限
Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp)
Router.Post("/apps", cfg.Auth.RequireCreate("app"), CreateApp)
// 超级管理员接口
Router.Get("/admin/users", cfg.Auth.PermAdmin("*"), AdminListUsers)
Router.Get("/admin/users", cfg.Auth.RequireAdmin("*"), AdminListUsers)
}
```
@ -241,16 +208,16 @@ func init() {
func init() {
// 从路径参数获取 appID (默认)
// GET /apps/{appID}
Router.Get("/apps/{appID}", cfg.Auth.PermRead("app:{appID}"), GetApp)
Router.Get("/apps/{appID}", cfg.Auth.RequireRead("app:{appID}"), GetApp)
// 从 query 参数获取
// GET /apps?appID=xxx
Router.Get("/apps", cfg.Auth.PermRead("app:{appID@query}"), GetApp)
Router.Get("/apps", cfg.Auth.RequireRead("app:{appID@query}"), GetApp)
// 多层嵌套
// GET /apps/{appID}/roles/{roleID}
Router.Get("/apps/{appID}/roles/{roleID}",
cfg.Auth.PermRead("app:{appID}:role:{roleID}"),
cfg.Auth.RequireRead("app:{appID}:role:{roleID}"),
GetRole,
)
}
@ -263,21 +230,21 @@ var Router = vigo.NewRouter().Use(cfg.Auth.Login())
func init() {
// 创建应用 - 系统级权限
Router.Post("/apps", cfg.Auth.PermCreate("app"), CreateApp)
Router.Post("/apps", cfg.Auth.RequireCreate("app"), CreateApp)
// 列出我的应用 - 只需登录
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.Get("/apps/{appID}", cfg.Auth.RequireRead("app:{appID}"), GetApp)
Router.Put("/apps/{appID}", cfg.Auth.RequireWrite("app:{appID}"), UpdateApp)
Router.Delete("/apps/{appID}", cfg.Auth.RequireAdmin("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)
Router.Post("/apps/{appID}/roles", cfg.Auth.RequireCreate("app:{appID}:role"), CreateRole)
Router.Get("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireRead("app:{appID}:role:{roleID}"), GetRole)
Router.Put("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireWrite("app:{appID}:role:{roleID}"), UpdateRole)
Router.Delete("/apps/{appID}/roles/{roleID}", cfg.Auth.RequireAdmin("app:{appID}:role:{roleID}"), DeleteRole)
}
```
@ -324,7 +291,7 @@ func CreateApp(x *vigo.X, req *CreateAppReq) (*AppResp, error) {
1. **全量管理接口**(如后台管理系统):
- 使用 `PermAdmin("*")` 或 `PermAdmin("app:*")`。
- 使用 `RequireAdmin("*")` 或 `RequireAdmin("app:*")`。
- 这类接口返回所有数据,必须严格控制权限。
2. **用户侧列表/搜索**(如“我的应用”):

@ -13,66 +13,76 @@
## 一、本地配置Local Config
存储在 `cfg/cfg.go`,仅包含系统启动必需的配置项。
存储在 `cfg/cfg.go`,仅包含系统启动必需的配置项。默认使用 SQLite 内存数据库,无需任何外部依赖即可运行。
### 1.1 配置项列表
### 1.1 YAML 配置示例
```yaml
# config.yaml 示例
dsn: "root:123456@tcp(127.0.0.1:3306)/vbase?charset=utf8&parseTime=True&loc=Local"
db: "mysql"
db:
type: "sqlite" # sqlite / mysql / postgres
dsn: "/tmp/vbase.db" # 数据库连接字符串
prefix: "vb_" # 表名前缀
redis:
addr: "localhost:6379"
addr: "memory" # memory内存模式或 redis://localhost:6379
password: ""
db: 0
# 系统密钥用于加密敏感数据JWT、数据库加密字段等
# 生产环境务必修改,建议 32 位以上随机字符串
key: "your-secret-key-change-in-production-min-32-characters"
host: "0.0.0.0"
port: 8080
jwt:
secret: "" # JWT 密钥(为空则使用 Key
access_expiry: 900 # Access Token 有效期(秒),默认 15m
refresh_expiry: 2592000 # Refresh Token 有效期(秒),默认 30d
issuer: "vbase" # JWT 签发者
cookie_path: "/" # Cookie Path默认 / 全站
cookie_prefix: "vb_" # Cookie Key 前缀
storage_path: "./data"
# 初始管理员配置(无人值守部署时使用)
# 当用户表为空且 username/password 都有值时,启动会自动创建该管理员
init_admin:
username: "admin"
password: "" # 生产环境务必设置强密码
username: "admin" # 管理员用户名
password: "" # 密码(为空则首注成为 admin
email: "admin@example.com"
```
### 1.2 配置项说明
| 配置项 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `dsn` | string | 是 | 数据库连接字符串 |
| `db` | string | 是 | 数据库类型mysql/postgres/sqlite |
| `redis` | object | 是 | Redis 配置,`addr: "memory"` 使用内存模式 |
| `key` | string | 是 | 系统密钥,用于加密敏感数据(建议 32 位以上) |
| `host` | string | 否 | 服务监听地址,默认 `0.0.0.0` |
| `port` | int | 否 | 服务监听端口,默认 `8080` |
| `storage_path` | string | 否 | 文件存储路径,默认 `./data` |
| `init_admin` | object | 否 | 初始管理员配置(无人值守部署时使用) |
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `db.type` | string | 否 | `sqlite` | 数据库类型sqlite / mysql / postgres |
| `db.dsn` | string | 否 | `/tmp/vbase.db` | 数据库连接字符串 |
| `db.prefix` | string | 否 | `vb_` | 表名前缀 |
| `redis.addr` | string | 否 | `memory` | Redis 地址,`memory` 使用内存模式 |
| `redis.password` | string | 否 | — | Redis 密码 |
| `redis.db` | int | 否 | `0` | Redis 数据库编号 |
| `key` | string | 是 | — | 系统密钥,用于加密敏感数据(建议 32 位以上) |
| `jwt.secret` | string | 否 | — | JWT 密钥(为空则使用 `key` |
| `jwt.access_expiry` | duration | 否 | `15m` | Access Token 有效期 |
| `jwt.refresh_expiry` | duration | 否 | `30d` | Refresh Token 有效期 |
| `jwt.issuer` | string | 否 | `vbase` | JWT 签发者名称 |
| `jwt.cookie_path` | string | 否 | `/` | Cookie Path 限定路径 |
| `jwt.cookie_prefix` | string | 否 | `vb_` | Cookie Key 前缀 |
### 1.3 Token 传送方式
**`init_admin` 详细说明:**
VBase 支持三种 Token 提取方式,优先级从高到低:
1. **Cookie**HttpOnly浏览器自动携带Key 为 `{cookie_prefix}access`
2. **Authorization Header**`Bearer <token>`
3. **Query 参数**`?access_token=<token>`
### 1.4 初始管理员配置
系统提供两种互斥的初始化管理员方式:
| 方式 | 触发条件 | 适用场景 |
|------|----------|----------|
| **自动创建**(本配置) | `username``password` 均已配置 | 无人值守部署、容器化环境 |
| **首注成为 admin** | `password` 为空,首个用户注册时 | 交互式部署、开发测试 |
| **自动创建** | `init_admin.username` 和 `init_admin.password` 均已配置 | 无人值守部署、容器化环境 |
| **首注成为 admin** | `init_admin.password` 为空 | 交互式部署、开发测试 |
**方式一:配置 init_admin推荐用于生产**
当满足以下条件时,**系统启动时**自动创建管理员:
- 用户表为空(首次部署)
- `init_admin.username``init_admin.password` 均已配置
```yaml
init_admin:
username: "admin"
@ -80,21 +90,29 @@ init_admin:
email: "admin@example.com"
```
效果:启动时自动创建 admin,后续注册的用户均为普通 user。
启动时自动创建管理员,后续注册的用户均为普通 user。
**方式二:首个注册用户成为 admin默认行为**
`init_admin.password` 为空时,保持原有逻辑:
- 第一个注册用户自动被授予 `admin` 角色
- 从第二个用户开始均为普通 user
`init_admin.password` 为空时,第一个注册用户自动被授予 `admin` 角色。
### 1.5 运行时钩子
```go
// OnUserCreate 用户创建成功后的回调钩子
// 可用于发送欢迎邮件、初始化用户资源等
cfg.OnUserCreate = func(userID string) error {
// 自定义逻辑
return nil
}
```
---
## 二、线上配置Settings
**字段说明:**
线上配置存储在数据库 `settings` 表中,通过管理后台或 API 实时修改,无需重启。
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `username` | string | 是 | 管理员用户名 |
| `password` | string | 条件 | 密码(配置则启用方式一,为空则启用方式二) |
| `email` | string | 否 | 邮箱地址 |
包括:应用名称、登录方式、密码字段配置、验证码开关、邮件/SMS 开关、OAuth 提供商等。
**其他注意事项:**
- 仅在没有用户时生效,已有用户则跳过
详见 API 的 `/api/settings``/api/info` 接口。

@ -2,16 +2,17 @@
## 1. 概览
VBase 是一个基于 Golang 的高性能后端基础框架旨在提供一套标准化的用户管理、作用域权限控制Scoped RBAC和 OAuth2 认证服务。项目采用分层架构设计,基于 `vigo` 框架构建,强调代码的可维护性、扩展性和安全性。
VBase 是一个基于 Golang 的高性能后端基础框架旨在提供一套标准化的用户管理、作用域权限控制Scoped RBAC和 OAuth2 认证服务。项目采用分层架构设计,基于 `vigo` 框架构建,支持 Session-based 认证、Cookie 令牌传送以及短信/邮箱验证码注册,强调代码的可维护性、扩展性和安全性。
## 2. 技术栈
- **语言**: Golang 1.22+
- **语言**: Golang 1.24+
- **Web 框架**: [vigo](https://github.com/veypi/vigo) (基于洋葱模型的高性能框架)
- **ORM**: GORM (支持 MySQL, PostgreSQL, SQLite 等)
- **配置管理**: `cfg` 包 (支持环境变量、配置文件)
- **认证**: JWT (JSON Web Token) + OAuth2
- **数据库**: 关系型数据库 (MySQL/PostgreSQL)
- **ORM**: GORM (支持 MySQL, PostgreSQL, SQLite)
- **配置管理**: `cfg` 包 (YAML 配置文件 + 环境变量)
- **认证**: Session + JWT (Access/Refresh Token)、Cookie 令牌传送
- **多因素认证**: 短信/邮箱验证码注册
- **数据库**: 默认为 SQLite可按需切换 MySQL/PostgreSQL
## 3. 系统架构
@ -32,12 +33,15 @@ Response <- [Global After Middleware] <------------------------------------+
│ ├── oauth/ # OAuth2 Provider 接口
│ ├── role/ # 角色管理接口
│ ├── user/ # 用户管理接口
│ ├── settings/ # 系统设置接口
│ ├── verification/ # 短信/邮箱验证码接口
│ └── init.go # 路由聚合与全局中间件配置
├── auth/ # 核心权限控制模块 (Scoped RBAC 实现)
├── cfg/ # 配置与基础设施 (DB, Redis, Log)
├── auth/ # 核心权限控制模块 (Scoped RBAC + Session 管理)
├── cfg/ # 配置与基础设施 (DB, Redis, JWT)
├── models/ # 数据模型定义 (GORM 结构体)
├── libs/ # 通用工具库
├── libs/ # 通用工具库 (jwt, cache, crypto, sms, email)
├── cli/ # 命令行入口
├── ui/ # 嵌入式管理界面 (vhtml)
└── docs/ # 文档
```
@ -63,7 +67,7 @@ Auth 模块是系统的核心安全组件实现了基于作用域Scope
系统提供 `auth.Auth` 接口和 `auth.Factory` 工厂,支持多应用集成:
1. **获取实例**: `myAuth := auth.Factory.New("my_scope")`
2. **基础权限**: `myAuth.PermRead("resource:id")` - 检查读取权限。
2. **基础权限**: `myAuth.RequireRead("resource:id")` - 检查读取权限。
3. **层级检查**:
- **Admin (Level 7)**: 拥有 `*` 或前缀匹配权限(向下继承)。
- **Standard**: 精确匹配且满足 Level 要求。
@ -71,14 +75,14 @@ Auth 模块是系统的核心安全组件实现了基于作用域Scope
#### 4.1.3 中间件流程
1. **LoginMiddleware**: 解析 JWT Token提取 UserID
2. **PermMiddleware**: 在业务 Handler 执行前拦截请求,调用 `Check` 进行鉴权。
1. **Login 中间件**: 从 Cookie / Authorization Header / Query 提取 Token解析 JWT 获取 UserID 和 SessionID验证 Session 有效性Redis 缓存 + DB 回退)
2. **Perm 中间件**: 在业务 Handler 执行前拦截请求,调用 `Check` 进行鉴权,支持动态权限码解析(从 Path/Query/Header 获取参数)
### 4.2 用户体系 (User Module)
- **User**: 核心用户实体,包含基本信息 (昵称、头像、邮箱等)
- **Identity**: 认证信息表,支持多种登录方式 (密码、OAuth、验证码等) 关联到同一用户。
- **Session**: 用户会话管理,用于记录登录状态和刷新 Token
- **User**: 核心用户实体,包含基本信息(用户名、密码、邮箱、手机号等),支持邮箱/手机验证状态追踪
- **Identity**: 认证信息表,支持多种登录方式密码、OAuth 第三方登录)关联到同一用户。
- **Session**: 登录会话管理,每次登录创建一个 Session记录设备信息和 IP支持版本号轮换防止并发刷新互踢和单独吊销
### 4.3 OAuth2 服务 (OAuth Module)
@ -91,12 +95,16 @@ Auth 模块是系统的核心安全组件实现了基于作用域Scope
## 5. 接口规范
### 5.1 请求处理
### 5.1 API 文档
路由启用了 `EnableApiDoc()`,可通过 `/_api.json` 查看所有注册接口的完整文档(包括参数、响应、中间件信息)。
### 5.2 请求处理
- **参数解析**: 利用 `vigo` 的泛型 Handler 机制,自动解析 Query, Path, Header, JSON Body 参数到结构体。
- **验证**: 结构体 Tag (`src`, `json`, `default`) 定义参数源和默认值。
### 5.2 响应格式
### 5.3 响应格式
统一使用 JSON 格式响应,由全局后置中间件 `common.JsonResponse` 处理:
@ -118,19 +126,30 @@ Auth 模块是系统的核心安全组件实现了基于作用域Scope
## 6. 数据库设计
推荐使用 `vigo.Model` 作为基类,统一包含以下字段:
所有模型以 `vigo.Model` 作为基类,统一包含以下字段:
- `ID`: UUID (varchar(36))
- `CreatedAt`: 创建时间
- `UpdatedAt`: 更新时间
- `DeletedAt`: 软删除标记
- `DeletedAt`: 软删除标记GORM
### 6.1 核心表
| 表 | 说明 |
|----|------|
| `users` | 用户表(用户名、密码、邮箱、手机、验证状态) |
| `identities` | 第三方身份绑定表 |
| `sessions` | 登录会话表设备信息、IP、版本号轮换 |
| `roles` | 角色表(系统/自定义) |
| `permissions` | 权限表(作用域隔离、支持按用户/角色授权) |
| `user_roles` | 用户-角色关联表 |
所有模型在 `models/init.go` 中注册,支持服务启动时自动迁移 (`AutoMigrate`)。
所有模型在 `models/init.go` 中注册,启动时通过 `Init()` 自动迁移 (`AutoMigrate`)。
## 7. 部署与运维
- **配置**: 支持 `.env` 文件和环境变量覆盖。
- **构建**: `go build -o vbase cli/main.go`
- **运行**: `./vbase -p 8080`
- **配置**: 支持 YAML 配置文件和环境变量覆盖,默认 SQLite 无需额外配置即可运行
- **运行**: `go run ./cli/*.go -p 4000``make run`
- **数据库迁移**: `go run ./cli/main.go db migrate`
## 8. 开发规范

@ -10,7 +10,7 @@ go get github.com/veypi/vbase
## 2. 初始化
在你的应用入口文件(如 `main.go``init.go`)中进行初始化。
在你的应用入口文件(如 `main.go`)中进行初始化。
```go
package main
@ -18,113 +18,133 @@ 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()
func main() {
// cfg.Global 已包含默认配置SQLite 内存数据库)
// 可通过环境变量或 YAML 文件覆盖
app := vigo.New("myapp", vbase.Router, cfg.Global, vigo.WithInit(vbase.Init))
panic(app.Run())
}
```
// 2. 创建你的应用 Auth 实例 (指定 Scope)
var AppAuth = auth.Factory.New("my_app")
VBase 自带嵌入式管理界面,启动后访问 `/vb/` 即可使用。
func init() {
// 3. 挂载 VBase 路由 (提供登录、用户管理等基础接口)
Router.Extend("/vb", vbase.Router)
### 2.1 挂载路由
// 4. 配置数据库连接 (如果尚未配置)
// export DSN="root:password@tcp(127.0.0.1:3306)/myapp?charset=utf8&parseTime=True"
}
VBase Router 已内置所有 API 路由(`/api/auth`、`/api/users`、`/api/roles`、`/api/oauth`、`/api/settings` 等)和 UI 路由(`/vb/`、`/v/`、`/vhtml/`)。
func main() {
// 5. 初始化数据库迁移
if err := vbase.Init(); err != nil {
panic(err)
}
如果你的应用需要自定义路由,将 VBase Router 挂载到你的 Router 上:
// 6. 启动服务
app := vigo.New("myapp", Router, cfg.Global, nil)
panic(app.Run())
```go
var Router = vigo.NewRouter()
func init() {
// 将 VBase 挂载到 /vb 前缀
Router.Extend("/vb", vbase.Router)
}
```
## 3. 使用权限系统
### 3.1 定义路由权限
VBase 通过 `cfg.Auth` 提供全局权限管理实例。所有中间件方法前缀为 `Require*`
使用 `AppAuth` 实例的中间件方法来保护你的路由。
### 3.1 定义路由权限
```go
func init() {
// 需要登录
Router.Use(AppAuth.Login())
// 所有路由需要登录
Router.Use(cfg.Auth.Login())
// 资源操作示例
// 假设你的资源是 "article"
// 创建文章 (需要 "article" 的创建权限 Level 1)
Router.Post("/articles", AppAuth.PermCreate("article"), CreateArticle)
Router.Post("/articles", cfg.Auth.RequireCreate("article"), CreateArticle)
// 读取文章 (需要 "article:{id}" 的读取权限 Level 2)
Router.Get("/articles/{id}", AppAuth.PermRead("article:{id}"), GetArticle)
// 读取文章 (需要对特定实例的读取权限 Level 2)
Router.Get("/articles/{id}", cfg.Auth.RequireRead("article:{id}"), GetArticle)
// 更新文章 (需要 "article:{id}" 的写入权限 Level 4)
Router.Put("/articles/{id}", AppAuth.PermWrite("article:{id}"), UpdateArticle)
// 更新文章 (需要对特定实例的写入权限 Level 4)
Router.Put("/articles/{id}", cfg.Auth.RequireWrite("article:{id}"), UpdateArticle)
// 删除文章 (需要 "article:{id}" 的管理员权限 Level 7)
Router.Delete("/articles/{id}", AppAuth.PermAdmin("article:{id}"), DeleteArticle)
// 删除文章 (需要对特定实例的管理员权限 Level 7)
Router.Delete("/articles/{id}", cfg.Auth.RequireAdmin("article:{id}"), DeleteArticle)
}
```
### 3.2 业务逻辑授权
### 3.2 权限码动态解析
权限码支持动态占位符,从不同来源获取值:
| 语法 | 来源 | 示例 |
|------|------|------|
| `{key}``{key@ctx}` | Context | `{appID}` |
| `{key@path}` | 路径参数 | `{appID@path}` |
| `{key@query}` | Query 参数 | `{appID@query}` |
| `{key@header}` | Header | `{Authorization@header}` |
在创建资源时,通常需要授予创建者管理权限。
### 3.3 业务逻辑授权
在创建资源时,授予创建者管理权限:
```go
func CreateArticle(x *vigo.X, req *ArticleReq) (*Article, error) {
// 1. 获取当前用户
userID := AppAuth.UserID(x)
userID := cfg.Auth.UserID(x)
// 2. 创建资源逻辑...
article := &Article{Title: req.Title, AuthorID: userID}
db.Create(article)
cfg.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)
}
permID := "article:" + article.ID
cfg.Auth.Grant(x.Context(), userID, permID, auth.LevelAdmin)
return article, nil
}
```
### 3.3 复杂场景:项目成员管理
### 3.4 多 Scope 权限隔离
假设你有一个项目管理系统,用户可以被邀请加入项目。
不同业务模块通过 Scope 实现权限隔离:
```go
// 邀请成员接口
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)
}
// 为不同应用创建独立的 Provider
var AppA_Auth = auth.Factory.New("app_a")
var AppB_Auth = auth.Factory.New("app_b")
// AppA 的用户权限不会影响 AppB
```
## 4. 配置说明
## 4. Session 管理
VBase 使用 Session + JWT 双 Token 机制:
VBase 使用 `cfg` 包管理配置,支持环境变量。
- **Access Token**:短期有效(默认 15 分钟),用于 API 认证
- **Refresh Token**:长期有效(默认 30 天),用于刷新 Access Token
- **Session**:记录登录设备信息和 IP支持版本号轮换防止并发刷新互踢
- `DB_DSN`: 数据库连接字符串
- `DB_TYPE`: 数据库类型 (mysql, postgres, sqlite)
- `JWT_SECRET`: JWT 签名密钥 (生产环境务必修改)
- `JWT_ISSUER`: Token 签发者
Token 默认通过 HttpOnly Cookie 传送。Session 可通过 `auth.RevokeSession`、`auth.RevokeOtherSessions`、`auth.RevokeAllSessions` 管理。
## 5. 配置说明
VBase 默认使用 SQLite 内存数据库(`/tmp/vbase.db`),无需任何外部依赖即可运行。
配置文件示例(`config.yaml`
```yaml
db:
type: "sqlite"
dsn: "/tmp/vbase.db"
redis:
addr: "memory"
key: "your-secret-key-min-32-characters"
jwt:
access_expiry: 900
refresh_expiry: 2592000
issuer: "vbase"
cookie_prefix: "vb_"
```
更多配置详情请参考 [配置文档](./configuration.md)。

@ -18,7 +18,7 @@ import (
"github.com/veypi/vigo"
)
const Version = "v1.1.1"
const Version = "v1.2.0"
var Router = vigo.NewRouter().EnableApiDoc()
var (

@ -22,9 +22,9 @@ go test -v ./tests/auth_test.go
### 1. 全局设置 (`main_test.go`)
- **TestMain**: 测试套件的入口点。
- 初始化 Vigo 应用程序。
- 初始化 Vigo 应用程序(带 VBase Router + Auth
- 设置内存 SQLite 数据库 (`:memory:`)。
- 模拟 Redis 客户端。
- 模拟 Redis 客户端(支持 Session 缓存验证)
- 运行所有测试。
- 执行后无需清理资源。

@ -1,7 +1,17 @@
# VBase 安全测试报告
## 测试执行时间
2026-02-18
2026-02-18原始 / 2026-06-06v1.2.0 更新)
## v1.2.0 修复状态
| 问题 | 严重度 | 状态 |
|------|--------|------|
| OAuth 客户端访问控制缺失 | 高 | 已修复 |
| 输入验证缺失 | 高 | 已修复 |
| Admin 无法访问所有组织 | 高 | 已修复Session 认证替代) |
| 并发操作问题 | 中 | 部分修复Session 版本号轮换) |
| 速率限制缺失 | 中 | 待实现 |
## 测试概述
本次测试针对 VBase 身份认证和权限管理系统进行了全面的安全测试包括权限系统、多租户隔离、OAuth2 安全、并发安全和边界情况测试。

Loading…
Cancel
Save