agentic_huge_data_base / wiki
页面 Dify · 8.1 租户模型与资源隔离·DeepWiki 中文全文译文

8.1 · 租户模型与资源隔离(Tenant Model and Resource Isolation)

应用编排与外部知识接入 · 本章是 Dify DeepWiki 中文译文的独立章节页,保留原始链接、源码锚点、模块标签和章节层级。

项目Dify 章节8.1 状态全文译文 模块测试、发布与运维、界面与交互、认证、权限与安全、文档对象与元数据
源码线索
  • api/controllers/console/auth/data_source_oauth.py
  • api/controllers/console/auth/email_register.py
  • api/controllers/console/auth/error.py
  • api/controllers/console/auth/forgot_password.py
  • api/controllers/console/auth/login.py
  • api/controllers/console/auth/oauth.py
  • api/controllers/console/explore/installed_app.py
  • api/controllers/console/workspace/account.py
  • api/controllers/console/workspace/members.py
  • api/controllers/console/workspace/model_providers.py
模块标签
  • 测试、发布与运维
  • 界面与交互
  • 认证、权限与安全
  • 文档对象与元数据
  • 系统架构

中文译文

租户模型与资源隔离(中文译文)

原始 DeepWiki 页面:https://deepwiki.com/langgenius/dify/8.1-tenant-model-and-resource-isolation
翻译时间:2026-05-27T08:44:29.808Z
翻译模型:deepseek-chat
原文字符数:14256
项目:Dify (dify)

---

租户模型与资源隔离

相关源文件

以下文件被用作生成此 Wiki 页面的上下文:

  • api/controllers/console/auth/data_source_oauth.py
  • api/controllers/console/auth/email_register.py
  • api/controllers/console/auth/error.py
  • api/controllers/console/auth/forgot_password.py
  • api/controllers/console/auth/login.py
  • api/controllers/console/auth/oauth.py
  • api/controllers/console/explore/installed_app.py
  • api/controllers/console/workspace/account.py
  • api/controllers/console/workspace/members.py
  • api/controllers/console/workspace/model_providers.py
  • api/controllers/console/workspace/models.py
  • api/controllers/console/workspace/plugin.py
  • api/controllers/console/workspace/workspace.py
  • api/libs/oauth.py
  • api/libs/oauth_data_source.py
  • api/models/account.py
  • api/models/api_based_extension.py
  • api/models/dataset.py
  • api/models/model.py
  • api/models/provider.py
  • api/models/source.py
  • api/models/task.py
  • api/models/tools.py
  • api/models/web.py
  • api/models/workflow.py
  • api/schedule/mail_clean_document_notify_task.py
  • api/services/account_service.py
  • api/templates/change_mail_confirm_old_template_zh-CN.html
  • api/templates/transfer_workspace_owner_confirm_template_en-US.html
  • api/templates/without-brand/transfer_workspace_owner_confirm_template_en-US.html
  • api/tests/unit_tests/libs/test_oauth_clients.py
  • api/tests/unit_tests/services/test_account_service.py
  • web/app/components/header/account-setting/members-page/__tests__/index.spec.tsx
  • web/app/components/header/account-setting/members-page/index.tsx
  • web/app/components/header/account-setting/members-page/operation/__tests__/index.spec.tsx
  • web/app/components/header/account-setting/members-page/operation/index.tsx

目的与范围

本文档描述了 Dify 的多租户架构,重点介绍了作为基本隔离边界的 Tenant 模型,以及所有资源如何通过 tenant_id 进行作用域限定。内容涵盖数据库模式设计、租户-账户关系、基于角色的访问控制,以及应用于应用、工作流、数据集和工具提供商的资源隔离模式。

关于认证方法(OAuth、SSO、API 密钥),请参见 8.2。关于基于角色的权限和访问控制详情,请参见 8.3。关于工作空间管理 API 和成员操作,请参见 8.4

---

核心租户实体

租户模型

Tenant 类代表一个工作空间,是 Dify 中的主要隔离边界。每个租户都是一个完全隔离的工作空间,拥有自己的资源、配置和成员列表。

数据库模式:

列名类型描述
idStringUUID主键,工作空间标识符(UUID v4)
nameString(255)工作空间名称
encrypt_public_keyLongText用于租户特定加密的 RSA 公钥
planString(255)订阅计划(基础版/专业版/团队版/企业版)
statusString(255)工作空间状态(正常/归档)
custom_configLongText自定义工作空间设置的 JSON 配置
created_atDateTime创建时间戳
updated_atDateTime最后更新时间戳

实现细节:

api/models/account.py 定义了 Tenant 类,该类使用 StringUUID 作为主键,并包含工作空间名称、状态和订阅计划等字段。

来源:api/models/account.py:242-277

---

租户-账户关系

多对多关联

Dify 通过 TenantAccountJoin 表实现了 TenantAccount 之间的多对多关系。每个账户可以属于多个租户(工作空间),每个租户可以有多个具有不同角色的账户。

图示:租户-账户-关联实体关系

erDiagram
    "Account (accounts)" ||--o{ "TenantAccountJoin (tenant_account_joins)" : "属于"
    "Tenant (tenants)" ||--o{ "TenantAccountJoin (tenant_account_joins)" : "拥有成员"
    "TenantAccountJoin (tenant_account_joins)" {
        string id PK
        string tenant_id FK "引用 tenants.id"
        string account_id FK "引用 accounts.id"
        boolean current "是否为当前活动工作空间"
        string role "TenantAccountRole"
        string invited_by FK "引用 accounts.id"
    }

来源:api/models/account.py:279-302

TenantAccountJoin 模式

关联表在成员级别强制执行租户隔离,并存储用户在该工作空间中的特定角色。

列名类型约束描述
idStringUUID主键关联记录标识符
tenant_idStringUUID外键,索引引用 tenants.id
account_idStringUUID外键,索引引用 accounts.id
currentBoolean默认值:false用户当前活动的工作空间
roleString(16)默认值:'normal'用户在此特定工作空间中的角色
invited_byStringUUID可为空发送邀请的账户 ID

来源:api/models/account.py:279-302

角色系统

TenantAccountRole 枚举定义了层级角色,用于管理租户内的权限。

图示:角色层级与代码实体

graph TD
    subgraph "自然语言角色"
        OwnerRole["所有者"]
        AdminRole["管理员"]
        EditorRole["编辑者"]
        NormalRole["普通用户"]
        DatasetOpRole["数据集操作员"]
    end

    subgraph "代码实体空间 (TenantAccountRole)"
        OWNER["TenantAccountRole.OWNER"]
        ADMIN["TenantAccountRole.ADMIN"]
        EDITOR["TenantAccountRole.EDITOR"]
        NORMAL["TenantAccountRole.NORMAL"]
        DATASET_OPERATOR["TenantAccountRole.DATASET_OPERATOR"]
    end

    OwnerRole --> OWNER
    AdminRole --> ADMIN
    EditorRole --> EDITOR
    NormalRole --> NORMAL
    DatasetOpRole --> DATASET_OPERATOR

    OWNER -->|"is_privileged_role()"| ADMIN
    ADMIN -->|"is_editing_role()"| EDITOR
    EDITOR -->|"is_dataset_edit_role()"| DATASET_OPERATOR

来源:api/models/account.py:19-77

---

资源作用域模式

通用 tenant_id 隔离

Dify 中的所有主要资源都包含一个 tenant_id 字段。这确保了每个查询都可以严格限定在当前工作空间上下文中。

图示:通过 tenant_id 进行资源作用域限定

graph TB
    subgraph "租户边界"
        T1["租户 (ID: uuid-1)"]
    end

    subgraph "作用域限定的资源"
        App1["App.tenant_id == uuid-1"]
        Workflow1["Workflow.tenant_id == uuid-1"]
        Dataset1["Dataset.tenant_id == uuid-1"]
        Provider1["Provider.tenant_id == uuid-1"]
        Tool1["BuiltinToolProvider.tenant_id == uuid-1"]
    end

    T1 --> App1
    T1 --> Workflow1
    T1 --> Dataset1
    T1 --> Provider1
    T1 --> Tool1

来源:api/models/model.py:72, api/models/workflow.py:187, api/models/dataset.py:180, api/models/provider.py:54, api/models/tools.py:94

包含 tenant_id 的资源模型
模型类别代码实体tenant_id 位置索引/约束
应用Appapi/models/model.py:72Index("app_tenant_id_idx", "tenant_id")
工作流Workflowapi/models/workflow.py:187Index("workflow_version_idx", "tenant_id", "app_id", "version")
知识库Datasetapi/models/dataset.py:180Index("dataset_tenant_idx", "tenant_id")
大语言模型(LLM)提供商Providerapi/models/provider.py:54UniqueConstraint("tenant_id", "provider_name", "provider_type", "quota_type")
工具BuiltinToolProviderapi/models/tools.py:94UniqueConstraint("tenant_id", "provider", "name")
API 工具ApiToolProviderapi/models/tools.py:158UniqueConstraint("name", "tenant_id")

---

租户上下文管理

账户租户关联

Account 模型在请求生命周期内维护当前活动租户上下文。current_tenant 设置器使用 TenantAccountJoin 解析用户在请求工作空间中的角色和成员身份。AccountService.load_user 函数根据 TenantAccountJoin.current 标志或第一个可用工作空间自动解析并设置 current_tenant

图示:AccountService 中的租户上下文解析

sequenceDiagram
    participant C as "AccountService.load_user"
    participant DB as "PostgreSQL (db.session)"
    participant A as "Account 实例"

    C->>DB: "select(Account).where(id=user_id)"
    DB-->>C: "Account 对象"
    C->>DB: "select(TenantAccountJoin).where(account_id=id, current=True)"
    alt 找到当前租户
        DB-->>C: "TenantAccountJoin"
        C->>A: "set_tenant_id(tenant_id)"
    else 没有当前租户
        C->>DB: "select(TenantAccountJoin).where(account_id=id).order_by(id.asc())"
        DB-->>C: "available_ta"
        C->>A: "set_tenant_id(available_ta.tenant_id)"
        C->>DB: "available_ta.current = True; commit()"
    end

来源:api/models/account.py:129-150, api/services/account_service.py:162-190

租户解析函数

代码库使用辅助函数,在只有资源 ID(如 app_id)可用时解析正确的 tenant_id,确保操作不会跨工作空间边界泄漏。

  • _resolve_app_tenant_id(app_id)api/models/model.py:71-75
  • _resolve_workflow_app_tenant_id(app_id)api/models/workflow.py:82-88

---

工具与提供商隔离

工具提供商多租户

工具配置(API 密钥、OAuth 令牌)严格按租户隔离。即使是内置工具,如果需要凭证,每个租户也需要一个 BuiltinToolProvider 记录。

图示:工具提供商隔离架构

graph LR
    subgraph "租户 A"
        T1["TenantID: A"]
        BTP1["BuiltinToolProvider"]
        ATP1["ApiToolProvider"]
    end
    subgraph "租户 B"
        T2["TenantID: B"]
        BTP2["BuiltinToolProvider"]
        ATP2["ApiToolProvider"]
    end
    T1 --> BTP1
    T1 --> ATP1
    T2 --> BTP2
    T2 --> ATP2

来源:api/models/tools.py:73-120, api/models/tools.py:128-180

模型提供商隔离

大语言模型(LLM)提供商通过 tenant_id 进行作用域限定。这包括 Provider 配置、ProviderModel 定义和 TenantDefaultModel 选择。

# api/models/provider.py:33-45
class Provider(TypeBase):
    # ...
    __table_args__ = (
        sa.PrimaryKeyConstraint("id", name="provider_pkey"),
        sa.Index("provider_tenant_id_provider_idx", "tenant_id", "provider_name"),
        sa.UniqueConstraint(
            "tenant_id", "provider_name", "provider_type", "quota_type", name="unique_provider_name_type_quota"
        ),
    )
    tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)

来源:api/models/provider.py:33-68, api/models/provider.py:163-180

---

安全与数据完整性

复合唯一约束

为防止跨租户的名称冲突,同时允许全局范围内存在重复名称,Dify 使用了包含 tenant_id 的复合唯一约束。

约束目的
providersunique_provider_name_type_quota每个租户/提供商的唯一配置
tool_builtin_providersunique_builtin_tool_provider每个租户的唯一凭证实例
tool_api_providersunique_api_tool_provider每个工作空间的唯一 API 工具名称
provider_modelsunique_provider_model_name每个租户的唯一模型配置
tenant_default_modelsunique_tenant_default_model_type每个租户每种类型一个默认模型

来源:api/models/provider.py:42-44, api/models/tools.py:81, api/models/tools.py:136, api/models/provider.py:124-126, api/models/provider.py:168

数据库索引策略

索引设计用于优化租户作用域的查询,通常将 tenant_id 作为复合索引的第一列。

  • Index("dataset_tenant_idx", "tenant_id")api/models/dataset.py:171
  • Index("workflow_version_idx", "tenant_id", "app_id", "version")api/models/workflow.py:183-184
  • Index("provider_tenant_id_provider_idx", "tenant_id", "provider_name")api/models/provider.py:41

来源:api/models/dataset.py:171, api/models/workflow.py:183-184, api/models/provider.py:41