跳到主要内容

08. Persistence 与 Security:状态、密钥和权限

8.1 数据库保存的是平台状态

packages/@n8n/db/src/entities 可以看到 n8n 的平台模型:workflow-entityexecution-entityexecution-datacredentials-entityuserprojectshared-workflowshared-credentialswebhook-entity 等。

工作流版本、发布状态、execution 历史和项目共享关系分别回答不同问题:当前编辑内容是什么、生产版本是什么、某次运行发生了什么、谁可以访问。不要把 workflow JSON 当成唯一事实来源。

8.2 Execution 数据和二进制数据

执行结果包含 JSON item,也可能包含图片、文件、音视频等 binary。二进制数据有独立的 binary-data 管理路径,可以落在文件系统、S3、Azure Blob 等存储。这样数据库不必承担所有大对象,但 execution JSON 中仍会保留 binary id/metadata。

需要关注:

  • packages/cli/src/executions/execution.service.ts
  • packages/cli/src/binary-data/database.manager.ts
  • packages/@n8n/blob-storage
  • docs/db.md@n8n/db 的连接/迁移代码

8.3 凭证加密和解析时机

凭证至少有三个时机:

保存:明文表单 → credential type 校验 → 加密字符串入库
执行:密文入库 → 解密 → 解析表达式/动态 token → 请求认证
展示:只返回脱敏 metadata,不把 secret 回送编辑器

CredentialsHelper 负责把 credential type 的认证声明转成实际 HTTP options。带过期 token 的 credential 可能在执行前 preAuthentication,并将刷新后的 token 写回,但源码特别保护“用户保存的是表达式”这一情况,避免把本次解析出的静态 token 覆盖掉动态表达式。

8.4 认证和浏览器会话

packages/cli/src/auth/auth.service.ts 的 JWT payload 不只包含 user id,还带密码派生 hash、browser id、MFA 使用状态和 embed 标记。中间件会检查:

  • cookie token 是否被 invalidated。
  • JWT 是否有效、用户是否存在。
  • MFA 是否已使用或需要 enrollment。
  • browser id 是否匹配,哪些 endpoint 必须豁免。
  • preview/unauthenticated endpoint 是否允许继续。

这不是单纯的“有 token 就放行”,而是把会话、浏览器来源和 MFA 状态合并成请求身份。

8.5 Project scope

权限不是只有 global role。ProjectScopeService 的关键逻辑是:如果用户的全局角色具备 scope,返回 null 表示可以访问所有项目;否则根据角色和 ProjectRelationRepository 查询可访问项目 id,再把范围注入查询。

request user + required scopes
→ global scope? → all projects
→ otherwise role scopes
→ project relations
→ repository query constrained by project ids

这解释了为什么 controller 能通过 scope 装饰器表达权限,而 service/repository 仍需要显式 project filter:权限校验和数据范围是两层防线。

8.6 设计取舍

执行状态和 workflow 分离支持历史查询、清理和重放,但要处理 schema 迁移、execution pruning 和版本对应。

密钥只在 helper 解密减少泄漏面,但任意节点执行上下文一旦允许读取 credentials,就必须严格审查日志、错误序列化和表达式访问。

项目级 scope比全局角色细粒度,适合团队协作;代价是每个查询、缓存和后台任务都必须带上正确的 project context。