日期范围: 2026-03-25 - 2026-03-31 摘要: v1.13.3 如期发布,聚焦流式可靠性与工作流修复;50 位贡献者参与;StreamsBroadcastChannel 并发问题由 QuantumGhost 重写解决;access token 退出失效安全 PR 终于取得实质性架构讨论进展;全局 httpx 客户端性能优化提上日程。
📦 版本发布
1. v1.13.3(Latest Stable)— 稳定性与流式修复
来源: github.com/langgenius/… 发布时间: 2026-03-27 类型: Stable 贡献者: 50 人(含 fatelei、QuantumGhost、lyzno1、tmimmanuel、Desel72 等);reaction 数 7(👍2 🎉5)
新功能:
- ✅ LLM / 问题分类器 / 变量提取器节点支持变量引用配置模型参数(#33082,@scdeng)
Bug 修复(重点):
- 🔥 StreamsBroadcastChannel 流式可靠性:修复 replay 和并发问题,确保前后端事件投递稳定(#34030 + #34061,@QuantumGhost)
- 🔥 工作流编辑器:修复粘贴节点保留 Loop/Iteration 元数据的问题;阻止 HumanInput 节点被粘贴到无效容器(#29983 + #34077)
- 🔥 运行时执行:恢复 prompt message 转换逻辑(v1.13.2 cherry-pick),修正
max_retries=0处理(#33666 + #33619 + #33688) - ✅ 知识库检索:保留 Web 响应中的引用元数据、修复 dataset icon 缺失崩溃、hit-count 查询过滤纠正、索引文档 chunk 预览恢复(#33778 + #33907 + #33757 + #33942)
底层改进:
- 大规模 testcontainers 迁移(20+ PR by @Desel72)
- EnumText 持续迁移(@tmimmanuel 系列 PR)
- TypedDict 类型化持续推进(@bittoby)
- 前端 toast 组件全面迁移至 Base UI Toast API(@lyzno1)
⚠️ 升级注意:Sandbox 默认 Python/Node.js 路径已在上个版本更新,如有现存 Sandbox 配置文件需手动更新路径。
🗓 本周发版节律
| 版本 | 类型 | 日期 | 亮点 |
|---|---|---|---|
| v1.13.3 | Stable | 2026-03-27 | 流式 BroadcastChannel 修复、变量引用模型参数、知识库修复 |
📊 本周共 1 次正式发布(1 stable),节奏回归正常:上周 1.13.3 里程碑延期后本周顺利发布。
🔥 热门话题
2. 🔄 StreamsBroadcastChannel 重写取代 xreadgroup PR
来源: github.com/langgenius/… 时间: 2026-03-25(PR #34030 merged) 热度: 替代 PR #33884
摘要: W13 追踪的 fatelei 的 xreadgroup PR #33884 被 QuantumGhost 关闭(superseded),QuantumGhost 另起 PR #34030 直接修复 StreamsBroadcastChannel 的 replay 和并发问题。#34030 采用了更简洁的方案——从流末尾开始读取消息,避免了 consumer group 设计的额外复杂度。后续 #34061 进一步修复并发问题。两个 PR 均已合入 v1.13.3。
3. 🔄🔐【跟进】access token 退出后仍有效 PR #31794 — 架构讨论取得突破
来源: github.com/langgenius/… 时间: 2026-03-17(QuantumGhost 评论)— 2026-03-31(仍 open) 热度: 安全高优先,5 参与者
摘要: 停滞 8 周的安全修复 PR #31794 本周取得实质性进展。laipz8200 此前以"stateless JWT 设计"为由 request changes,但 QuantumGhost 于 2 周前提出折中方案:引入 SessionRevocationStorage 接口(含 revoke()、is_revoked()、expunge() 方法),默认 NullSessionRevocationStorage 不引入任何状态,部署者可选择 Redis 后端。fatelei 据此重写代码(force-push 多次),Copilot AI Review 也提出了 SHA-256 fallback 等改进建议。目前 laipz8200 的 requested changes 仍未解除,但架构方向已明确。这是近 2 个月来该 PR 最活跃的一周。
4. 🚀 性能优化:全局 httpx 客户端(#34309 / #34311)
来源: github.com/langgenius/… 时间: 2026-03-31(今日 4 小时前 open) 热度: 13 条评论
摘要: fatelei 提出 #34309 性能优化提案:将每次请求新建 httpx 客户端改为全局复用,减少连接开销。对应 PR #34311(size:L)同日提交,已有 13 条评论讨论中。此优化对高并发场景下的 API 调用延迟有直接正面影响。
5. 🔐 Docker Compose 硬编码默认密钥安全风险(#34321)
来源: github.com/langgenius/… 时间: 2026-03-31(1 小时前 open) 热度: 新 issue
摘要: mahdirajaee 报告 docker-compose.yaml 中硬编码默认 secrets(如数据库密码、API key 等)对生产部署构成安全风险。自托管用户若不手动修改默认值,可能暴露敏感数据。相关联 issue #34320 同时报告 api/worker/worker_beat 缺少 healthcheck 定义。
6. 🐛 MCP 工具从 1.7.1 升级到 1.14.0-rc1 后失效(#34275)
来源: github.com/langgenius/… 时间: 2026-03-30(20 小时前 open) 热度: 5 条评论
摘要: 用户从 Dify 1.7.1 升级到 1.14.0-rc1 后 MCP 工具完全不可用。此问题与 #24224(MCP session per-call reinitialization)可能相关,属于跨大版本升级的兼容性问题。
🚀 新功能 / 合并 PR
7. feat: 变量引用支持模型参数配置(#33082,已入 v1.13.3)
来源: github.com/langgenius/… 时间: 2026-03-27(v1.13.3 发布)
摘要: @scdeng 实现 LLM、问题分类器、变量提取器节点中模型参数的变量引用支持。此功能允许用户在工作流中动态配置模型参数(如 temperature、max_tokens 等),大幅增强工作流灵活性。
8. feat: inner API 端点支持管理员 DSL 导入/导出(#34059)
来源: github.com/langgenius/… 时间: 2026-03-27(已 merged)
摘要: @zhangx1n 新增内部管理 API 端点,支持管理员级别的 DSL 导入/导出操作。适用于企业级批量应用迁移和备份场景。
9. chore: 供应链安全加固(#34317)
来源: github.com/langgenius/… 时间: 2026-03-31(已 merged)
摘要: @hyoban 提交供应链安全改进,减少依赖链中潜在的安全风险。属于 CI/CD 安全最佳实践系列改进。
10. test: 大规模 testcontainers 迁移(@Desel72 系列)
来源: 多个 PR(#34304, #34305, #34306, #34286 等) 时间: 2026-03-28 — 2026-03-31
摘要: @Desel72 和 @YB0y 本周持续推进 testcontainers 迁移工作,将 mock-based 测试替换为真实数据库集成测试,覆盖 datasets controller、workflow controller、import controller、apikey controller 等多个模块。@Desel72 同时开始 sessionmaker().begin() 重构系列(#34283, #34284)。测试基础设施质量持续提升。
🐛 活跃 Bug 与问题
11. 💪 Workflow 用量应分别追踪 input/output token(#34315)
来源: github.com/langgenius/… 时间: 2026-03-31(3 小时前 open)
摘要: @JokerQyou 提出功能请求:工作流用量统计应分别追踪 input/output tokens 而非只显示总量,便于成本分析和优化。
12. 🔄【跟进】MCP session per-call reinitialization #24224 — 里程碑移至 next
来源: github.com/langgenius/… 时间: 本周无新评论 热度: 仍 open,assigned to @55Kamiryo
摘要: QuantumGhost 在 2 周前将此 issue 的里程碑从 v1.13.1 移至 "next"。55Kamiryo 的 PR #28621(MCP session reuse per workflow run)仍在维护,但短期内不太可能合入。该问题影响所有需要多步 MCP 工具链的用户(如 playwright navigate → screenshot)。
13. 🔄【跟进】1.14.0-rc1 CORS/Skill 创建 bug #32816 — 仍 open
来源: github.com/langgenius/… 时间: 2026-03-31(SmallStom 4 小时前评论) 热度: 9 条评论
摘要: 1.14.0-rc1 的 Skill 创建 CORS + ghost record + 500 error 问题仍 open。社区用户分享了 FILES_API_URL 配置为外网域名的变通方案,但根本问题(Ghost record 缺乏事务回滚)未修复。无人 assigned。
14. 🔄【跟进】userinput.files LEGACY 字段导致 Agent 节点故障 #33976 — 仍 open
来源: github.com/langgenius/… 时间: 上周开启,本周无新进展
摘要: Cloud 用户报告 Workflow 中不可删除的 userinput.files LEGACY 字段导致所有 Agent 节点报错"file type parameter file not supported in agent"。dosubot 确认为已知问题(hardcoded readonly system variable),Cloud 用户无可用的解决方案。与 #30835 关联。
📊 数据概览
| 维度 | 数据 |
|---|---|
| GitHub Open Issues | 372(与 W13 持平) |
| GitHub Open PRs | 407(较 W13 的 424 下降,大量 PR 合入 v1.13.3) |
| 版本发布 | 1 次(v1.13.3 stable) |
| v1.13.3 贡献者 | 50 人 |
| HN 热帖 | 本周无 Dify 专题 |
| Reddit 热帖 | 本周无新帖 |
| 本周核心主题 | v1.13.3 发布、流式 BroadcastChannel 修复、access token 安全 PR 进展、全局 httpx 优化 |
| 当前最新稳定版 | v1.13.3 |
| 在途重点 | access token 安全修复 #31794、MCP session 复用 #28621、全局 httpx 客户端 #34311 |
🔍 深入分析:Access Token 安全修复架构演进(PR #31794)
PR: fix: fix access token is still valid after logout #31794 Issue: #31793 — 登出后 access token 仍有效 状态: Open(+479/-11,8 文件变更,29 条讨论,14 checks 运行中) 关联: EE-1525(企业版内部 issue,由 douxc 确认)
1. 问题本质
Dify 的认证流程基于 JWT access token + Redis-backed refresh token 的双 token 模型。登出时,AccountService.logout() 仅删除 Redis 中存储的 refresh_token,而 JWT access token 一旦签发即不可撤销——这是经典的无状态 JWT 设计取舍。
实际影响:用户点击「退出登录」后,在 access token 过期(默认 TTL)之前,该 token 仍然可以正常访问所有 API。对于 SaaS/多租户场景(Dify Cloud),这是一个真实的安全风险:离职员工、被踢出的协作者、或被盗的 session 在退出后仍有操作窗口。
2. 时间线与关键人物
| 时间 | 事件 | 角色 |
|---|---|---|
| 01-31 | fatelei 提交初版 PR:JWT 加入 jti 声明,登出时将 jti 写入 Redis 黑名单 | @fatelei(Contributor) |
| 02-06 | douxc 关联 EE-1525(企业版需求确认) | @douxc(Member) |
| 02-10 | Copilot AI 第一轮 review:建议改善代码风格、性能、测试覆盖 | Copilot |
| ~03 初 | laipz8200 请求修改并阻塞合并:「The stateless JWT design was chosen with performance and ease of use in mind; there is currently no reason to introduce additional state to change it.」 | @laipz8200(Member,CODEOWNER) |
| ~03 初 | fatelei 回应:「no additional state, it just add a access token blacklist in redis」 | @fatelei |
| 03-17 | QuantumGhost 提出 SessionRevocationStorage 接口方案——折中妥协 | @QuantumGhost(Contributor,CODEOWNER) |
| 03-17 | fatelei 据此重写实现,force-push 新版本(feat: add session revoke storage) | @fatelei |
| 03-17 | Copilot AI 第三轮 review:2 个 Medium 级安全建议 | Copilot |
| W14 | laipz8200 的 requested changes 仍未解除,PR 仍处于 blocked 状态 | — |
3. 架构之争:无状态 vs 有状态
这是一场经典的 JWT 安全性辩论,三方立场如下:
laipz8200 的立场(守)——纯无状态 JWT
"The stateless JWT design was chosen with performance and ease of use in mind; there is currently no reason to introduce additional state to change it."
- JWT 的核心价值是无状态验证:只需 SECRET_KEY 即可在任意节点验证,无需查询存储
- 引入黑名单 = 每次请求都要查 Redis → 本质上退化为有状态 session
- 如果需要即时撤销,不如直接用 session-based auth
fatelei 的立场(攻)——实用安全优先
"no additional state, it just add a access token blacklist in redis to disable user visit api after logout"
- 安全缺陷是现实存在的(企业版 EE-1525 也确认了需求)
- Redis 查询只在黑名单命中时有额外开销(miss 是 O(1) EXISTS 操作)
- 不改变 JWT 本身的签发和验证逻辑,只是增加一层可选检查
QuantumGhost 的折中(和)——Strategy Pattern
"What about extract an interface named SessionRevocationStorage, then let deployers of Dify specify SessionRevocationStorage to use while deploying Dify?"
这个方案当前已被 fatelei 实现,是 PR 的最新架构:
4. 最新架构详解
┌──────────────────────────────────────────────────────────┐
│ SessionRevocationStorage (Protocol) │
│ │
│ revoke(token_id, expiration_time) → None │
│ is_revoked(token_id) → bool │
│ expunge() → None │
└─────────────────┬───────────────────┬────────────────────┘
│ │
┌─────────────┴──────┐ ┌────────┴──────────────────┐
│ NullSessionRevoke │ │ RedisSessionRevoke │
│ Storage (默认) │ │ Storage │
│ │ │ │
│ revoke → no-op │ │ revoke → SETEX key TTL 1 │
│ is_revoked → False │ │ is_revoked → EXISTS key │
│ expunge → no-op │ │ expunge → no-op (TTL 自清)│
└────────────────────┘ └───────────────────────────┘
关键设计决策:
| 决策点 | 选择 | 理由 |
|---|---|---|
| 默认行为 | NullSessionRevocationStorage(禁用) | 兼容现有部署,不破坏无状态语义 |
| 配置方式 | SESSION_REVOCATION_STORAGE=null|redis | 运维层面可选启用,无代码侵入 |
| 存储键 | passport:blacklist:jti:{jti} | 使用 JWT 标准 jti 声明做唯一标识 |
| TTL 策略 | SETEX(key, token剩余生存时间, "1") | token 过期后黑名单记录自动清除,不会无限增长 |
| 单例模式 | _singleton + factory get_session_revocation_storage() | 避免每次请求创建新实例 |
| 旧 token 兼容 | 无 jti 的 token fallback 使用原始 token 字符串 | 过渡窗口内的向后兼容 |
请求流程(启用 Redis 模式后):
用户请求 → JWT 签名验证 → [pass] → SessionRevocationStorage.is_revoked(jti)
│
┌────┴────┐
│ Redis │
│ EXISTS │
└────┬────┘
存在? → 401 Token has been revoked
不存在? → 放行,返回 payload
登出流程:
POST /logout → extract_access_token(request)
→ AccountService.logout(account, access_token)
→ PassportService.revoke(token)
→ decode(token, verify_signature=False)
→ extract jti + exp
→ storage.revoke(jti, exp_datetime)
→ SETEX "passport:blacklist:jti:{jti}" {remaining_ttl} "1"
→ delete refresh_token from Redis(原有逻辑)
5. 遗留问题与风险
| # | 问题 | 严重度 | 状态 |
|---|---|---|---|
| 1 | laipz8200 的 requested changes 未解除 | 🔴 阻塞 | 尽管架构已采纳 QuantumGhost 的折中方案,laipz8200 作为 CODEOWNER 的 review 仍为 blocking |
| 2 | 旧 token 使用原始字符串做 Redis key | 🟡 安全 | Copilot 指出:token_id = payload.get("jti") or token 会将完整 JWT 明文存入 Redis key,泄露 token material 给有 Redis 访问权限的人。建议改用 SHA-256 摘要 |
| 3 | 黑名单 key 前缀重复定义 | 🟡 维护 | passport:blacklist:jti: 分别硬编码在 passport.py 和 RedisSessionRevocationStorage 中,未来可能不一致 |
| 4 | Redis 高可用依赖 | 🟡 可靠性 | QuantumGhost 指出:启用 Redis 模式后,如果 Redis 不可用,is_revoked() 会抛异常 → 所有认证请求被阻断。需要考虑 fallback 策略(如 Redis 不可达时 fail-open) |
| 5 | 过渡窗口 | 🟢 低 | PR 合并后,已签发的旧 token(无 jti)在过期前不能被优雅地撤销。窗口长度 = access token 的当前 TTL |
6. 行业对比
| 方案 | 即时撤销 | 每请求开销 | 复杂度 | 谁在用 |
|---|---|---|---|---|
| 纯无状态 JWT(Dify 现状) | ❌ | 零额外 I/O | 低 | 大量小型项目 |
| JWT + jti 黑名单(PR #31794 Redis 模式) | ✅ | 1× Redis EXISTS | 中 | Auth0, Firebase(类似) |
| 短 TTL JWT + Refresh Token Rotation | ⚠️ 延迟撤销 | 零额外 I/O | 中 | OAuth 2.0 标准推荐 |
| Opaque Token + Session Store | ✅ | 1× DB/Redis 查询 | 高 | GitHub, GitLab |
QuantumGhost 的方案本质上是 给部署者选择权:默认零开销(Null),需要时开启 Redis 黑名单。这在开源项目中是比较明智的策略——既不强制所有用户承担额外延迟,又为安全敏感场景提供了标准化出口。
7. 展望
- 短期:需要 laipz8200 重新 review 并解除 blocking。考虑到 QuantumGhost 的方案已经将默认行为设为 Null(完全保持现有无状态语义),laipz8200 原始的异议理论上已被解决
- 中期:Copilot 提出的 SHA-256 fallback、key 前缀去重建议需要在合并前处理
- 长期:如果 Dify 推进 OAuth 2.0 / OIDC 集成(已有相关 issue),可考虑将 SessionRevocationStorage 扩展为更通用的 token 生命周期管理层