乐于分享
好东西不私藏

S1(终篇)-源码学习篇-08-多租户 + 权限:企业级 AI 平台的安全基石——万悟 RBAC 与租户隔离

S1(终篇)-源码学习篇-08-多租户 + 权限:企业级 AI 平台的安全基石——万悟 RBAC 与租户隔离

多租户 + 权限:企业级 AI 平台的安全基石——万悟 RBAC 与租户隔离源码拆解

📌 本文是《从零吃透企业级 AI 平台:元景万悟源码学习手记》系列第一季·源码学习篇的第 8 篇(终篇)🎯 读完本文你将:① 理解多租户架构的三种隔离模型 ② 掌握 RBAC 权限设计与中间件鉴权实现 ③ 能在万悟中配置完整的组织架构与权限策略⏱️ 预计阅读时间:35 分钟 | 动手实践:60 分钟💻 前置要求:已完成前 7 篇,对万悟整体架构有全局认知


插一句后续计划:台风“白海豚”来了,在家里蹲着顺便把第一季最后一篇完结掉,后续计划出第一季番外篇,把一些正文主干没有讲透但在落地细节也需要注意的地方写一写,然后才会展开写第二季,讲实际的项目配套。

第一季的文章中代码块偏长,后续风格会把大代码块改成"关键 10-20 行 + 说明",完整代码收进 ## 附录。

后面可能1-3天发一篇,一周发2-4篇,看时间情况安排。


一、这篇文章要解决什么问题?

前 7 篇我们拆解了万悟的所有"能力模块":模型接入、RAG、GraphRAG、Agent、MCP、工作流。但有一个问题始终没正面回答:

当 50 个部门、500 个用户同时使用这个平台时,怎么保证 A 部门看不到 B 部门的知识库?怎么保证实习生不能删除 CEO 的智能体?怎么保证每个租户的 API 调用量不互相影响?

这就是多租户(Multi-Tenancy)+ 权限控制(RBAC)要解决的问题。

Demo 级项目:一个用户,所有权限,数据混在一起 → 能跑就行企业级平台:N 个租户 × M 个角色 × K 种资源 → 安全是生命线

💡 一句话总结:前 7 篇决定了平台"能做什么",这一篇决定了平台"能不能上线"。

万悟作为面向央企/国企的 AI 平台,安全合规是第一优先级。今天我们把它的权限体系完整拆开。


二、核心概念:用大白话讲清楚

2.1 多租户:一栋公寓楼

💡 类比:多租户就像公寓楼

  • 一栋楼(一套代码、一个集群)住很多户(租户)
  • 每户有自己的钥匙(API Key / Token)
  • 每户只能进自己的房间(数据隔离)
  • 物业(平台管理员)能进所有房间,但住户之间互相进不去

关键问题:隔离到什么程度?

2.2 三种隔离模型

模型
说明
隔离强度
成本
适用场景
共享数据库 + 租户字段
所有租户数据在同一张表,用 tenant_id 区分
⭐⭐
SaaS、中小规模
共享数据库 + Schema 隔离
同一数据库实例,每个租户独立 Schema
⭐⭐⭐
中大型企业
独立数据库
每个租户独立数据库实例
⭐⭐⭐⭐⭐
金融、政务、央企

万悟采用混合模型

  • 默认:共享数据库 + tenant_id 字段(轻量、易运维)
  • 高安全租户:可配置独立数据库(满足等保/密评要求)

💡 信创多数据库支持:万悟的数据库层设计了一个"可插拔"的抽象——不是绑死 MySQL。通过 WANWU_DB_NAME 环境变量,可以在三种关系型数据库中切换:

数据库
端口
适用场景
MySQL
3306
默认引擎,中小规模
TiDB
4000
国产分布式数据库,大规模/高可用
OceanBase
2881
蚂蚁自研,金融级强一致

所有微服务共 9 个独立 schema(iam/model/app/rag/assistant/knowledge/mcp/operate/opencoze),通过 GORM 统一访问,切换数据库只需改环境变量+连接串。

2.3 RBAC:角色-权限模型

💡 类比:RBAC 就像公司的门禁系统

  • 你不是直接拿钥匙开每扇门(用户 → 权限)
  • 而是你的工牌(角色) 决定了你能进哪些门
  • HR 给你分配工牌(用户 → 角色),工牌上刻着权限列表(角色 → 权限)
  • 你升职了?换工牌就行,不用重新配每扇门
用户(User) ──N:M──→ 角色(Role) ──1:N──→ 权限(Permission)   │                    │                      │ 张三               ”部门管理员”          ”kb:read”, ”kb:write”, 李四               ”普通成员”            ”agent:read 王五               ”平台管理员”          ”ALL”

2.4 万悟的权限模型

层级
说明
示例
平台级
超级管理员,管所有租户
联通研究院运维团队
租户级
租户管理员,管本租户所有资源
某省分公司 IT 部门
空间级
工作空间隔离(部门/项目组)
"AI 研发部"空间
资源级
具体资源的 CRUD 权限
知识库 A 只读、智能体 B 可编辑

2.5 API Key 与认证

认证方式
适用场景
有效期
JWT Token
前端用户登录
2h(可刷新)
API Key
后端服务间调用
长期(可吊销)
OAuth 2.0
第三方系统集成
按授权范围
mTLS
内部微服务通信
证书有效期

三、万悟是怎么实现的?(源码篇)

3.1 定位源码

⚠️ 诚实说明:以下 3.2–3.7 的代码是教学重建版——用最小代码讲清认证、鉴权、租户隔离的核心逻辑。万悟真实的权限体系基于 Casbin(RBAC 策略引擎)+ JWT + RSApkg/rsa-util/),代码分布在以下路径:

# 万悟真实源码结构(Go 单体仓库)internal/iam-service/# 身份与租户服务(gRPC 微服务)├── client/# IAM 客户端├── config/# 认证配置└── server/grpc/# gRPC 服务入口(用户/角色/权限/租户 CRUD)internal/bff-service/# BFF 网关(HTTP 入口,中间件挂载点)# 认证 → 租户注入 → 限流 → 鉴权 中间件链在此pkg/rsa-util/# RSA 加解密工具(密钥管理)# 万悟使用 Casbin 作为 RBAC 策略引擎,非自研权限框架

3.2 认证中间件

// 教学重建版(对应真实路径:internal/bff-service/ 中间件 + internal/iam-service/ JWT 验证)// AuthMiddleware 是全局认证中间件// 每个请求都必须经过这里funcAuthMiddleware(jwtService *JWTService) gin.HandlerFunc {    return func(c *gin.Context) {        // Step 1: 提取 Token        // 支持两种来源:Authorization Header 或 API Key Header        token := c.GetHeader(”Authorization”)        apiKey := c.GetHeader(”X-API-Key”)        var claims *Claims        var err error        if token != ”” {            // JWT 认证(前端用户)            token = strings.TrimPrefix(token, ”Bearer ”)            claims, err = jwtService.Verify(token)            if err != nil {                c.AbortWithStatusJSON(401, gin.H{”error”: ”invalid or expired token”})                return            }        } else if apiKey != ”” {            // API Key 认证(服务间调用)            claims, err = jwtService.VerifyAPIKey(apiKey)            if err != nil {                c.AbortWithStatusJSON(401, gin.H{”error”: ”invalid api key”})                return            }        } else {            c.AbortWithStatusJSON(401, gin.H{”error”: ”authentication required”})            return        }        // Step 2: 将用户信息注入上下文        // 后续所有 handler 都可以从 context 中获取当前用户        c.Set(”user_id”, claims.UserID)        c.Set(”tenant_id”, claims.TenantID)   // ← 关键!租户 ID        c.Set(”roles”, claims.Roles)        c.Set(”space_id”, claims.SpaceID)        c.Next()    }}

📌 关键洞察tenant_id 在认证阶段就被注入上下文。后续所有数据库查询都会自动带上 WHERE tenant_id = ?,实现行级数据隔离。这不是可选的——是架构强制的。

3.3 租户上下文与数据隔离

// 教学重建版(对应真实路径:internal/bff-service/ 租户中间件)// TenantMiddleware 确保所有数据操作都在租户边界内funcTenantMiddleware() gin.HandlerFunc {    return func(c *gin.Context) {        tenantID := c.GetString(”tenant_id”)        if tenantID == ”” {            c.AbortWithStatusJSON(403, gin.H{”error”: ”tenant context missing”})            return        }        // 将 tenant_id 注入到数据库查询上下文        // 所有 Repository 层的方法都会从 context 中读取这个值        ctx := context.WithValue(c.Request.Context(), TenantKey, tenantID)        c.Request = c.Request.WithContext(ctx)        c.Next()    }}// ===== Repository 层示例 =====// 教学重建版(对应真实路径:internal/knowledge-service/ 数据查询层)// ListByTenant 查询知识库列表// 注意:tenant_id 从 context 中获取,而非参数传入// 这保证了”不可能忘记加租户过滤”func(r *KBRepository) List(ctx context.Context) ([]KnowledgeBase, error) {    tenantID := ctx.Value(TenantKey).(string)    var kbs []KnowledgeBase    // GORM 查询自动带租户过滤    err := r.db.WithContext(ctx).        Where(”tenant_id = ?”, tenantID).  // ← 强制隔离        Find(&kbs).Error    return kbs, err}

💡 设计哲学:万悟的租户隔离是架构级强制的,而非"开发者自觉"。tenant_id 通过 context 传递,Repository 层统一从 context 读取。即使某个开发者写新接口时"忘了"加过滤,框架层的 TenantMiddleware 也会拦截。

3.4 RBAC 鉴权中间件

// 教学重建版(对应真实路径:Casbin 策略引擎 + internal/bff-service/ 鉴权中间件)// RequirePermission 是一个路由级中间件// 用法:router.GET(”/kb”, RequirePermission(”kb:read”), handler.ListKB)funcRequirePermission(requiredPerm string) gin.HandlerFunc {    return func(c *gin.Context) {        userID := c.GetString(”user_id”)        tenantID := c.GetString(”tenant_id”)        roles := c.GetStringSlice(”roles”)        // Step 1: 超级管理员直接放行        if contains(roles, ”super_admin”) {            c.Next()            return        }        // Step 2: 查询用户的所有权限(带缓存)        // 缓存策略:Redis,TTL 5 分钟        // Key: ”perms:{tenant_id}:{user_id}”        perms, err := getPermissionsWithCache(c, tenantID, userID)        if err != nil {            c.AbortWithStatusJSON(500, gin.H{”error”: ”permission check failed”})            return        }        // Step 3: 检查是否拥有所需权限        // 支持通配符:拥有 ”kb:*” 等同于拥有 ”kb:read”, ”kb:write”, ”kb:delete”        if !hasPermission(perms, requiredPerm) {            c.AbortWithStatusJSON(403, gin.H{                ”error”: fmt.Sprintf(”permission denied: requires '%s'”, requiredPerm),            })            return        }        c.Next()    }}// hasPermission 检查权限(支持通配符)funchasPermission(userPerms []string, required string) bool {    for _, p := range userPerms {        if p == required || p == ”*” {            return true        }        // 通配符匹配:”kb:*” 匹配 ”kb:read”        if strings.HasSuffix(p, ”:*”) {            prefix := strings.TrimSuffix(p, ”:*”)            if strings.HasPrefix(required, prefix+”:”) {                return true            }        }    }    return false}

3.5 权限定义与角色模型

// 教学重建版(对应真实路径:internal/iam-service/ 权限模型 + Casbin 策略)// 万悟的权限采用 ”资源:操作” 格式var AllPermissions = []string{    // 知识库    ”kb:read”, ”kb:write”, ”kb:delete”, ”kb:admin”,    // 智能体    ”agent:read”, ”agent:write”, ”agent:delete”, ”agent:admin”,    // 工作流    ”workflow:read”, ”workflow:write”, ”workflow:execute”, ”workflow:admin”,    // 模型    ”model:read”, ”model:write”, ”model:admin”,    // MCP 工具    ”mcp:read”, ”mcp:write”, ”mcp:admin”,    // 用户管理    ”user:read”, ”user:write”, ”user:admin”,    // 租户管理    ”tenant:admin”,    // 审计日志    ”audit:read”,}// 预定义角色var DefaultRoles = map[string][]string{    ”viewer”: {        ”kb:read”, ”agent:read”, ”workflow:read”, ”model:read”,    },    ”member”: {        ”kb:read”, ”kb:write”,        ”agent:read”, ”agent:write”,        ”workflow:read”, ”workflow:execute”,        ”model:read”,        ”mcp:read”,    },    ”admin”: {        ”kb:*”, ”agent:*”, ”workflow:*”, ”model:*”, ”mcp:*”,        ”user:read”, ”user:write”,        ”audit:read”,    },    ”super_admin”: {”*”},}

3.6 租户级限流

// 教学重建版(对应真实路径:internal/bff-service/ 限流中间件)// TenantRateLimiter 基于租户的 API 限流// 防止某个租户的大量请求影响其他租户funcTenantRateLimiter(redis *redis.Client) gin.HandlerFunc {    return func(c *gin.Context) {        tenantID := c.GetString(”tenant_id”)        // 从配置中获取该租户的限额        // 不同套餐:免费版 100 RPM,企业版 10000 RPM        limit := getTenantRateLimit(tenantID)        // 滑动窗口限流(Redis ZSET 实现)        key := fmt.Sprintf(”ratelimit:%s:%s”, tenantID, time.Now().Format(”200601021504”))        now := time.Now().UnixNano()        pipe := redis.Pipeline()        // 移除窗口外的记录        pipe.ZRemRangeByScore(c, key, ”0”, fmt.Sprintf(”%d”, now-int64(limit.Window)))        // 统计当前窗口内的请求数        countCmd := pipe.ZCard(c, key)        // 添加当前请求        pipe.ZAdd(c, key, &redis.Z{Score: float64(now), Member: now})        pipe.Expire(c, key, limit.Window*time.Second)        pipe.Exec(c)        count := countCmd.Val()        if count >= limit.MaxRequests {            c.AbortWithStatusJSON(429, gin.H{                ”error”: ”rate limit exceeded”,                ”retry_after”: limit.Window,            })            return        }        // 将剩余配额写入响应头(方便客户端感知)        c.Header(”X-RateLimit-Remaining”, fmt.Sprintf(”%d”, limit.MaxRequests-count))        c.Next()    }}

📌 企业级细节:限流的 Key 包含 tenant_id,意味着每个租户有独立的配额。A 租户把配额用完了,不影响 B 租户。这是多租户平台的基本要求。

3.7 路由挂载(全景图)

// 教学重建版(对应真实路径:internal/bff-service/ 路由注册)func SetupRoutes(r *gin.Engine) {    // 公开接口(无需认证)    public := r.Group(”/api/v1”)    {        public.POST(”/auth/login”, authHandler.Login)        public.POST(”/auth/register”, authHandler.Register)        public.GET(”/health”, healthHandler.Check)    }    // 需认证的接口    authorized := r.Group(”/api/v1”)    authorized.Use(        AuthMiddleware(jwtService),      // 1. 认证:你是谁?        TenantMiddleware(),              // 2. 租户:你属于哪个租户?        TenantRateLimiter(redisClient),  // 3. 限流:你的配额够吗?    )    {        // 知识库(需要 kb:read 权限)        kb := authorized.Group(”/knowledge-bases”)        kb.Use(RequirePermission(”kb:read”))        {            kb.GET(””, kbHandler.List)            kb.GET(”/:id”, kbHandler.Get)            // 写操作需要更高权限            kb.POST(””, RequirePermission(”kb:write”), kbHandler.Create)            kb.DELETE(”/:id”, RequirePermission(”kb:delete”), kbHandler.Delete)        }        // 智能体        agent := authorized.Group(”/agents”)        agent.Use(RequirePermission(”agent:read”))        {            agent.GET(””, agentHandler.List)            agent.POST(””, RequirePermission(”agent:write”), agentHandler.Create)            agent.POST(”/:id/chat”, agentHandler.Chat) // 对话只需 read        }        // 管理接口(需要 admin 权限)        admin := authorized.Group(”/admin”)        admin.Use(RequirePermission(”user:admin”))        {            admin.GET(”/users”, adminHandler.ListUsers)            admin.POST(”/roles”, adminHandler.CreateRole)            admin.GET(”/audit-logs”, RequirePermission(”audit:read”), adminHandler.AuditLogs)        }    }}

💡 中间件执行顺序认证 → 租户注入 → 限流 → 权限检查。这个顺序不能乱——没认证就不知道是谁,不知道是谁就不知道属于哪个租户,不知道租户就没法限流。


四、动手跑通(实践篇)

4.1 配置组织架构

在万悟管理后台:

  1. 「租户管理」→ 创建租户:   - 名称:华东分公司   - 套餐:企业版(10000 RPM)   - 数据隔离:共享数据库
  2. 「用户管理」→ 创建用户:
用户
角色
空间
张总
admin
全局
李工
member
AI 研发部
王实习
viewer
AI 研发部
  1. 「空间管理」→ 创建空间:   - AI 研发部(李工、王实习)   - 市场部(独立空间,数据互不可见)

4.2 验证权限隔离

测试
操作
预期结果
数据隔离
王实习登录,查看知识库列表
只看到 AI 研发部空间的知识库
权限控制
王实习尝试删除知识库
403:requires 'kb:delete'
跨租户
用华东分公司的 Token 访问华南分公司的 KB ID
404(查不到,因为 tenant_id 不匹配)
限流
用脚本快速发 200 个请求
前 100 个成功,后面 429
API Key
创建一个只有 kb:read 权限的 API Key
能查不能改

4.3 创建 API Key

# 通过管理 API 创建受限 API Keycurl -X POST https://wanwu.example.com/api/v1/admin/api-keys \  -H ”Authorization: Bearer ” \  -H ”Content-Type: application/json” \  -d '{    ”name”: ”报表服务专用”,    ”permissions”: [”kb:read”, ”workflow:execute”],    ”expires_at”: ”2027-01-01T00:00:00Z”,    ”rate_limit”: 1000  }'# 响应{  ”api_key”: ”wk_live_a1b2c3d4e5f6...”,  ”name”: ”报表服务专用”,  ”permissions”: [”kb:read”, ”workflow:execute”],  ”created_at”: ”2026-08-01T11:00:00Z”}

⚠️ 安全提醒:API Key 只在创建时返回一次明文,之后只存哈希。务必当场保存。

4.4 审计日志

万悟记录所有敏感操作:

时间
用户
操作
资源
结果
11:02:33
李工
kb:delete
KB-0042
❌ 403 权限不足
11:05:12
张总
kb:delete
KB-0042
✅ 成功
11:10:45
API Key (报表服务)
kb:read
KB-0001
✅ 成功

📌 合规价值:对于央企/国企,审计日志是等保测评的硬性要求。万悟的审计日志不可篡改(写入后只追加),保留期可配置(默认 180 天)。


五、自己造一个 Mini 版(Deep Dive)

🎯 目标:用 Python 实现一个 90 行的多租户 RBAC 系统

# mini_rbac.py# 依赖:pip install flask pyjwtimport jwt, time, functoolsfrom flask import Flask, request, jsonify, gapp = Flask(__name__)SECRET = ”your-secret-key”# ===== 1. 模拟数据 =====USERS = {    ”u001”: {”name”: ”张总”, ”tenant”: ”T1”, ”roles”: [”admin”]},    ”u002”: {”name”: ”李工”, ”tenant”: ”T1”, ”roles”: [”member”]},    ”u003”: {”name”: ”王实习”, ”tenant”: ”T1”, ”roles”: [”viewer”]},    ”u004”: {”name”: ”赵总”, ”tenant”: ”T2”, ”roles”: [”admin”]},}ROLE_PERMS = {    ”admin”: [”kb:*”, ”agent:*”, ”user:read”],    ”member”: [”kb:read”, ”kb:write”, ”agent:read”],    ”viewer”: [”kb:read”, ”agent:read”],}# 模拟知识库(含 tenant_id)KNOWLEDGE_BASES = [    {”id”: ”KB-01”, ”name”: ”研发文档”, ”tenant”: ”T1”},    {”id”: ”KB-02”, ”name”: ”市场资料”, ”tenant”: ”T1”},    {”id”: ”KB-03”, ”name”: ”财务数据”, ”tenant”: ”T2”},]# ===== 2. 认证中间件 =====def auth_required(f):    @functools.wraps(f)    def wrapper(*args, **kwargs):        token = request.headers.get(”Authorization”, ””).replace(”Bearer ”, ””)        try:            payload = jwt.decode(token, SECRET, algorithms=[”HS256”])        except jwt.ExpiredSignatureError:            return jsonify({”error”: ”token expired”}), 401        except jwt.InvalidTokenError:            return jsonify({”error”: ”invalid token”}), 401        g.user_id = payload[”user_id”]        g.tenant_id = payload[”tenant_id”]        g.roles = payload[”roles”]        return f(*args, **kwargs)    return wrapper# ===== 3. RBAC 鉴权 =====def require_permission(perm):    def decorator(f):        @functools.wraps(f)        def wrapper(*args, **kwargs):# 收集用户所有权限            user_perms = set()            for role in g.roles:                user_perms.update(ROLE_PERMS.get(role, []))# 检查权限(支持通配符)            if not _has_perm(user_perms, perm):                return jsonify({”error”: f”forbidden: requires '{perm}'”}), 403            return f(*args, **kwargs)        return wrapper    return decoratordef _has_perm(user_perms, required):    for p in user_perms:        if p == required or p == ”*”:            return True        if p.endswith(”:*”) and required.startswith(p[:-1]):            return True    return False# ===== 4. 业务接口 =====@app.route(”/login”, methods=[”POST”])def login():    user_id = request.json[”user_id”]    user = USERS.get(user_id)    if not user:        return jsonify({”error”: ”user not found”}), 404    token = jwt.encode({        ”user_id”: user_id,        ”tenant_id”: user[”tenant”],        ”roles”: user[”roles”],        ”exp”: time.time() + 7200,    }, SECRET, algorithm=”HS256”)    return jsonify({”token”: token, ”user”: user[”name”]})@app.route(”/knowledge-bases”)@auth_required@require_permission(”kb:read”)def list_kb():# 租户隔离:只返回当前租户的数据    result = [kb for kb in KNOWLEDGE_BASES if kb[”tenant”] == g.tenant_id]    return jsonify({”data”: result, ”tenant”: g.tenant_id})@app.route(”/knowledge-bases”, methods=[”POST”])@auth_required@require_permission(”kb:write”)def create_kb():    name = request.json[”name”]    new_kb = {”id”: f”KB-{len(KNOWLEDGE_BASES)+1:02d}”, ”name”: name, ”tenant”: g.tenant_id}    KNOWLEDGE_BASES.append(new_kb)    return jsonify({”created”: new_kb}), 201@app.route(”/knowledge-bases/”, methods=[”DELETE”])@auth_required@require_permission(”kb:delete”)def delete_kb(kb_id):# 双重校验:权限 + 租户归属    kb = next((k for k in KNOWLEDGE_BASES if k[”id”] == kb_id), None)    if not kb or kb[”tenant”] != g.tenant_id:        return jsonify({”error”: ”not found”}), 404    KNOWLEDGE_BASES.remove(kb)    return jsonify({”deleted”: kb_id})# ===== 5. 测试 =====if __name__ == ”__main__”:    app.run(debug=True, port=5000)# 测试命令:# 1. 登录获取 Token#    curl -X POST localhost:5000/login -H ”Content-Type: application/json” -d '{”user_id”:”u003”}'## 2. 用 viewer 的 Token 查知识库(成功,有 kb:read)#    curl localhost:5000/knowledge-bases -H ”Authorization: Bearer ”#    → 只返回 T1 的 KB-01, KB-02(看不到 T2 的 KB-03)## 3. 用 viewer 的 Token 删知识库(403,没有 kb:delete)#    curl -X DELETE localhost:5000/knowledge-bases/KB-01 -H ”Authorization: Bearer ”#    → {”error”: ”forbidden: requires 'kb:delete'”}## 4. 用 T2 用户的 Token 访问 T1 的知识库(404,租户隔离)#    → 即使知道 KB-01 的 ID,也查不到

🎉 这 90 行就是万悟权限体系的最小可行实现:JWT 认证 → 租户注入 → RBAC 鉴权 → 数据过滤。万悟在此基础上加了:Redis 权限缓存、API Key 管理、OAuth 2.0、mTLS、审计日志、动态角色、空间级隔离、等保合规……但核心逻辑就是你看到的这三个装饰器:@auth_required → @require_permission → WHERE tenant_id = ?


六、系列总结 & 延伸阅读

本文要点回顾

  1. ✅ 多租户隔离三种模型:行级(tenant_id)→ Schema 级 → 实例级,万悟默认行级 + 可选实例级
  2. ✅ RBAC = 用户 → 角色 → 权限,权限格式 资源:操作,支持通配符
  3. ✅ 中间件链:认证 → 租户注入 → 限流 → 鉴权,顺序不可乱
  4. ✅ 租户隔离是架构强制的(context 传递),非开发者自觉
  5. ✅ 审计日志不可篡改,满足等保/密评合规要求

课后作业

  • 在万悟中创建 2 个租户、3 个角色、5 个用户,验证隔离和权限
  • 创建受限 API Key,用 curl 测试权限边界
  • 查看审计日志,确认所有操作被记录
  • 跑通 Mini RBAC,理解认证→鉴权→隔离的完整链路
  • 思考:如果要支持"临时授权"(如:给外部审计员 7 天只读权限),架构该怎么扩展?

🎓 系列回顾:8 篇文章,一个完整的企业级 AI 平台

篇目
主题
核心收获
第 1 篇
架构总览
微服务全景、技术选型、本地部署
第 2 篇
模型接入
多模型适配、负载均衡、流式输出
第 3 篇
传统 RAG
分块→嵌入→检索→生成 Pipeline
第 4 篇
GraphRAG
知识图谱构建、多跳检索、混合模式
第 5 篇
Agent 引擎
ReAct 循环、Function Calling、安全护栏
第 6 篇
MCP 协议
工具解耦、JSON-RPC、MCP Server 开发
第 7 篇
工作流引擎
DAG 编排、拓扑排序、条件分支
第 8 篇
多租户权限
RBAC、租户隔离、限流、审计
┌─────────────────────────────────────────────────────────────┐│                    万悟平台架构全景                           ││                                                             ││  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐       ││  │ 模型层  │  │ 知识层  │  │ 智能层  │  │ 编排层  │       ││  │(第2篇)  │  │(第3,4篇)│  │(第5,6篇)│  │(第7篇)  │       ││  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘       ││       └─────────────┴─────────────┴─────────────┘           ││                          │                                  ││                   ┌──────▼──────┐                           ││                   │  安全基座   │                           ││                   │  (第8篇)    │                           ││                   │ 认证·鉴权   │                           ││                   │ 隔离·限流   │                           ││                   │ 审计·合规   │                           ││                   └─────────────┘                           │└─────────────────────────────────────────────────────────────┘

下一步学什么?

方向
推荐资源
深入 RAG
《RAG 实战课》(极客时间)、LlamaIndex 源码
深入 Agent
LangGraph 文档、AutoGen 论文
深入分布式
《Designing Data-Intensive Applications》
深入安全
OWASP Top 10、等保 2.0 标准
参与贡献
万悟 GitHub Issues(good first issue 标签)

参考资源

  • 元景万悟 GitHub:https://github.com/UnicomAI/wanwu
  • Casbin(万悟使用的 RBAC 策略引擎):https://casbin.org/
  • RBAC 论文:Role-Based Access Controls (Sandhu et al., 1996)
  • JWT 规范:RFC 7519 https://datatracker.ietf.org/doc/html/rfc7519
  • 等保 2.0:GB/T 22239-2019
  • Gin 中间件文档:https://gin-gonic.com/docs/examples/using-middleware/

📮 这是本系列的最后一篇。 感谢你从第 1 篇一路跟到这里 🎉如果这个系列对你有帮助,请 点赞 + 收藏 + 关注,这是对创作者最大的鼓励🔔 后续可能推出「番外篇」:性能调优、生产部署、故障排查等实战主题

我们下一个系列见 👋


📱 关注公众号,追更不迷路

本系列文章首发于微信公众号「农夫三拳有点癫」,每周更新源码拆解与架构实战。

在微信扫描下方二维码即可关注:

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-09 20:01:52 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/917976.html
  2. 运行时间 : 0.216133s [ 吞吐率:4.63req/s ] 内存消耗:4,684.29kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=ae9f2577aabc5eeddf35e9b84437fcef
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 4.22 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.11 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001358s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001692s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000723s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000644s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001746s ]
  6. SELECT * FROM `set` [ RunTime:0.000603s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001477s ]
  8. SELECT * FROM `article` WHERE `id` = 917976 LIMIT 1 [ RunTime:0.001237s ]
  9. UPDATE `article` SET `lasttime` = 1786276912 WHERE `id` = 917976 [ RunTime:0.002252s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000592s ]
  11. SELECT * FROM `article` WHERE `id` < 917976 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001130s ]
  12. SELECT * FROM `article` WHERE `id` > 917976 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001029s ]
  13. SELECT * FROM `article` WHERE `id` < 917976 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001761s ]
  14. SELECT * FROM `article` WHERE `id` < 917976 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001606s ]
  15. SELECT * FROM `article` WHERE `id` < 917976 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001527s ]
0.219996s