# 搭完"积木"之后,我给开源框架接通了企微和开放平台 > 上次聊了怎么用"搭积木"的方式搭后台,这次聊聊怎么把积木搭进企业生态——企微集成 + 能力开放平台。 --- ## 写在前面:后台框架的"孤岛困境" 上一篇《当 90% 的中后台还在重复造轮子》发出后,不少同学在评论区问了一个问题: > "框架内部能力确实全,但企业里不可能只用你一个系统。审批要推到企微,外部系统要调你的接口,这些怎么搞?" 好问题。说实话,这也是我做完低代码、工作流、AI 之后,一直在想的事。 **一个后台框架如果只管自己内部那摊事,做得再好也是信息孤岛。** 企业真实的长这样: - 员工日常用**企业微信**沟通,审批、通知、待办都希望在企微里完成 - 外部 ERP / CRM / 小程序要调你的**业务接口**,不能每个对接方都给一套账号密码 - 管理员配完企微和开放平台后,**自己都不知道配得对不对**,得让开发去翻日志 - 企微通讯录一变,**本地用户表就脱节了**,新员工登不进来,离职员工还在系统里 这些事单独拎出来都不难,难的是**每接一个项目都要重来一遍**。于是我把企业微信协同和能力开放做进了 Forge,今天聊聊这两块。 > 先放个演示地址,文章里说的所有东西都能在线试:http://www.dlforgelab.com:8084/forge/login (账号 `admin` / `123456`) --- ## 一、企业微信集成:不是"扫码登录",是整个协同层 先说最大的误解——很多人以为"企微集成"就是加个企业微信扫码登录。不是。 ### 1.1 多数框架的企微集成长什么样 | 能力 | 多数框架的现状 | |------|----------------| | 登录 | 支持企微扫码,但 OAuth 回调直接把用户信息丢给前端,前端再提交后端 | | 通讯录 | 手动导入或写一次性脚本同步,人员变动靠人工记得改 | | 消息 | 自己写企微 API 调用代码,散落在各个业务模块里 | | 待办 | 企微收不到审批通知,或者收到后点了跳过去是一个没有鉴权的 URL | | 安全 | Secret 明文存数据库,回调验签全靠自己手写,出了问题不好查 | **核心问题:每加一个平台(飞书、钉钉),这些逻辑全要再写一遍。** ### 1.2 Forge 的做法:先建通用底座,企微只是第一个适配器 我没有把企微逻辑写死在登录、用户、消息、流程这些模块里。而是先做了一层**平台无关的企业协同 SPI**,企业微信只是它的第一个完整适配器。 架构长这样: ``` forge-starter-collaboration(通用 SPI 层) ├── Provider Connector 接口 ← 飞书/钉钉以后只需实现这个 ├── 能力枚举(LOGIN/DIRECTORY/MESSAGE/TODO) ├── 统一上下文 + Provider Registry └── 合同测试套件 + Fake Provider ← 证明编排层不依赖企微分支 forge-plugin-collaboration(编排插件) ├── 连接管理(一个租户可配多个企业连接) ├── 应用管理(每个连接下可挂多个物理应用,Secret 只存一份) ├── 通讯录同步(全量 + 增量 + 冲突处理 + 问题单) ├── 消息投递(统一 COLLABORATION 渠道,逐接收人结果) ├── 待办投影(Flowable 任务 → 企微卡片,状态始终以 Forge 为准) └── 回调收件箱(验签/解密/防重放/去重/异步补偿) ``` **一句话总结:飞书、钉钉后续只需实现 Connector,不动组织同步、消息、待办和运维主链路。** ### 1.3 安全这件事,我花了最多精力 企业集成涉及身份认证、人员停用和流程操作,安全出问题就是大事。几个关键设计: **登录链路彻底重写了 OAuth 流程:** | 环节 | 旧做法(多数框架) | Forge 的做法 | |------|-------------------|-------------| | OAuth state | 前端生成或不校验 | 服务端一次性生成并保存,绑定连接/租户/动作 | | 回调返回 | 完整 AuthUser 返回前端 | 只返回短期一次性 `socialTicket`,前端拿不到第三方用户信息 | | 身份来源 | 信任前端提交的 socialUuid | 只认服务端校验过的连接和外部身份 | | 账号合并 | 手机号/邮箱相同自动合并 | **禁止自动合并**,只认通讯录已建立的映射,防止错误合并员工 | **凭据安全:** 所有 Secret、Token、Callback Token、EncodingAESKey 全部走**版本化 AES-GCM 认证加密**存储,管理端只返回"已配置"状态和固定掩码。空值保留(不改不动),轮换用比较更新防并发恢复旧值。认证加密不可用时**失败关闭,不回退明文**。 **待办回调不能越权审批:** 企微卡片点击后,Forge 重新校验:外部身份 → 接收人 → 租户 → 任务当前状态 → 办理权限。任务已完成、已撤回或操作者无权时,返回业务已失效并更新外部卡片,不重复执行。 ### 1.4 通讯录同步:不是一次性脚本,是完整运维闭环 | 能力 | 说明 | |------|------| | 全量同步 | 读取完整快照 → 校验父子关系 → 分阶段落库 → 成功后才处理未出现记录 | | 增量处理 | 成员新增/变更/离职/转部门,定时全量校准兜底 | | 权限边界 | 同步只管本连接拥有的映射,Forge 角色/组织内角色/手工岗位不覆盖 | | 失败保护 | 拉取中断时不误停用存量人员(这个坑很常见) | | 问题单 | 冲突、失败进队列,管理员可绑定/忽略/重试 | | 同步日志 | 批次、阶段、计数、游标、状态全可查 | **"企微是通讯录权威来源,Forge 是权限权威来源"**——这个边界很重要。同步不会误删你手工配的角色和权限。 ### 1.5 管理端:配完就知道行不行 新增了一整套管理界面(演示站可体验): | 页面 | 干什么 | |------|--------| | 连接管理 | 配置企业连接,管理登录/通讯录/消息/待办应用,Secret 永不明文返回 | | 连通测试 | 按能力执行 Token/读取/测试消息验证,**配完立刻知道行不行** | | 同步日志 | 查看同步批次和阶段统计 | | 问题单 | 冲突/失败队列,可人工处理 | | 映射查看 | 查看外部部门/成员/岗位/标签与 Forge 的映射 | | 投递管理 | 消息和待办投递状态,失败可人工重试 | | 回调事件 | 回调元数据和 processing 状态(不返回解密正文) | --- ## 二、统一能力开放平台:把内部能力安全地"开出去" 第二块是能力开放平台。这个更硬核——它解决的是"外部系统怎么安全地调你的接口"。 ### 2.1 为什么要做这个 客户场景很真实:外围系统(ERP、小程序、第三方应用)需要调 Forge 的业务接口——建单、发起审批、查询数据。老做法是给每个对接方开一个账号,写一段鉴权代码,然后在 Controller 里手动校验权限。 问题在哪? - **没有统一鉴权**:每个接口各写各的,漏一个就是越权 - **没有幂等**:网络重试就重复建单 - **没有限流**:对接方一个循环就把你打垮 - **没有审计**:出了问题查不到谁调了什么 - **管理员没法自助**:配完授权不知道能不能调,要开发去翻日志 ### 2.2 Forge 的做法:一个网关兜住所有外部调用 核心是一个统一 REST 开放网关: ``` 外部请求 │ ├── 1. 认证(OAuth Bearer 或 HMAC-SHA256 签名) ├── 2. 防重放(timestamp ±5分钟 + nonce 一次性校验) ├── 3. 授权(能力是否已发布?客户端是否已授权?) ├── 4. 身份校验(required_actor_type:USER/SERVICE/BOTH) ├── 5. 限流(读 120次/分,写 20次/分,可配置) ├── 6. 幂等(写操作强制 Idempotency-Key,命中返回首次响应快照) ├── 7. Schema 校验(按已发布版本校验请求体) ├── 8. 执行(CapabilityExecutor + ExecutionIdentity 上下文) ├── 9. 统一响应 {code, message, requestId, timestamp, data} └── 10. 审计入库(不保存请求/响应原文) ``` **这条链路上每一步都是可配置、可审计、可拒绝的。** 任何一步不通过,直接返回明确的错误码,不往下走。 ### 2.3 两种认证模式,覆盖主流对接场景 | 模式 | 认证方式 | 身份类型 | 适用场景 | |------|---------|---------|---------| | OAuth Bearer | `Authorization: Bearer fdu_...` | SERVICE 或 USER | 现代对接,支持用户委托 | | HMAC 签名 | `X-Forge-App-Id` + `timestamp` + `nonce` + `signature` | 仅 SERVICE | 传统系统对接,不依赖 OAuth | 签名串固定为 `appId\ntimestamp\nnonce\nMETHOD\npath\nsha256(body)`,HMAC-SHA256,常量时间比较。简单、安全、可复制。 **关键安全设计:** 签名密钥是 KEK 加密可逆存储(因为验签要还原原文),和现有 Bearer 凭据的哈希存储完全分离——不改动现有凭据的安全语义。 ### 2.4 能力注册:三种来源,受控发布 不是什么接口都能开放。能力要先注册、发布、授权,才能被外部调用: | 能力来源 | 说明 | 安全控制 | |---------|------|---------| | **业务动作**(BUSINESS_ACTION) | 低代码业务对象的增删改查 | 按字段白名单过滤 | | **流程动作**(FLOW_ACTION) | 发起流程、提交业务申请、审批 | 强制 USER 委托身份 | | **系统服务**(SYSTEM_SERVICE) | 代码显式注册的服务(如"启动已发布流程") | 管理端不可填任意 URL,只选注册项 | **系统服务是关键设计——** 管理员不能在后台填一个任意 URL 就开放出去。系统服务只能由代码注册,发布时固定流程模型和允许变量,调用者不能指定 modelKey、tenantId、userId 或 initiator。这避免了"把内部接口直接代理出去"的风险。 ### 2.5 调用指南:管理员配完就知道怎么调 这是我花精力最多的地方。以前配完授权,管理员不知道行不行,要开发翻日志。现在: **四步式调用指南:** 1. **选择客户端** → 展示可调用状态和阻断原因(不返回模糊 403) 2. **调用前检查** → 逐条诊断:网关开关、客户端状态、grant 状态、actor/auth/权限 3. **契约与示例** → 递归参数表(含中文名称、类型、必填、含义、示例)+ Curl/Java 17 示例 4. **在线测试** → 真实走 `/oauth2/token` + `/openapi/v1/capabilities/:code/invoke`,有副作用的能力二次确认 **认证方式一键切换:** OAuth 和 HMAC 示例通过单一选择器切换,URL、能力编码、Header、Body 与真实网关契约完全一致。 **文档下载:** - **Markdown 调用文档**:概述、地址、主体要求、认证、Header、参数表、业务规则、权限、幂等/限流、错误码、OAuth/HMAC 示例、排障——外围开发不用看 Forge 源码就能接入 - **OpenAPI 3.1 JSON**:可直接导入 Swagger/Apifox **一句话:管理员配完,自己就能判断能不能调、怎么调、为什么不能调。** ### 2.6 身份桥接:外部用户怎么变成 Forge 用户 外部系统调用流程审批类能力时,需要一个真实的 Forge 用户身份。Forge 提供两条路: | 方式 | 说明 | 适用场景 | |------|------|---------| | **受信 OIDC Token Exchange** | 外围系统提交受信 IdP 签发的 JWT,Forge 按 `issuer + subject` 自动映射现有用户并签发短期 USER Token | 有统一身份提供方 | | **客户端签名用户断言** | 无统一 OIDC 时,客户端用 RSA 私钥签发短期 JWT(最长 2 分钟),Forge 验签后按预绑定 `sub` 委托真实用户 | 无统一 IdP | **安全边界很明确:** - 外部 JWT 只接受管理员显式配置的 HTTPS issuer 和 audience,默认不配置即失败关闭 - 只允许 RS256,禁止 `none` 和共享密钥 - 手机号匹配默认关闭,只有验签 + 防重放 + 格式校验全通过后才允许租户内唯一匹配 - 不为不存在的 Forge 用户自动建号 - 断言和 OIDC 使用不同 `subject_token_type`,验签失败不互相回退 ### 2.7 审计:每一次调用都可追溯 每次调用(含被拒绝的)写 `ai_capability_invocation_log`,记录: `requestId / capabilityCode / version / clientId / actorType / actorUserId / tenantId / resultCode / httpStatus / schemaPath / durationMs` **不保存:** 请求 Body、响应 Body、Token、Secret、签名、Nonce 原文、用户手机号。 控制台可按 `requestId` 串联:入口接收 → 认证完成 → 授权完成 → 幂等命中 → 执行成功/失败。排障不用翻服务器日志。 --- ## 三、两块拼在一起:企业集成的完整故事 企微集成和能力开放平台不是孤立的两个功能,拼在一起就是一条完整的企业集成链路: ``` ┌─────────────────────────────────┐ │ Forge Admin │ │ │ 企业微信 ───────→ │ 企微协同层 │ (通讯录/登录) │ ├── 人员同步 → sys_user │ │ ├── 安全登录 → Sa-Token 会话 │ │ ├── 消息投递 → 消息中心 │ │ └── 待办投影 → Flowable 任务 │ │ │ 外部系统 ───────→ │ 能力开放平台 │ (ERP/小程序/ │ ├── OAuth/HMAC 认证 │ 第三方应用) │ ├── 能力注册/发布/授权 │ │ ├── 网关调用 → CapabilityExecutor│ │ └── 审计追溯 → 调用日志 │ │ │ │ 低代码 + 工作流 + AI + 多租户 │ └─────────────────────────────────┘ ``` **一个真实场景走一遍:** 1. 企业微信通讯录同步 → Forge 自动建立用户映射 2. 员工在企微收到审批卡片 → 点击安全跳转到 Forge 待办 → 完成审批 3. 外部 ERP 系统通过 HMAC 签名调用 Forge 开放接口 → 发起采购审批流程 4. 流程审批人通过企微待办完成审批 → 结果回写业务系统 5. 全程:内部用户走企微协同,外部系统走能力开放,两套链路各自安全 **以前这套东西从零搭,至少一个月。现在配一配,跑通验证,几天就能上线。** --- ## 四、算笔账:自己搭 vs 用 Forge | 能力 | 自己从零搭 | 用 Forge | |------|-----------|---------| | 企微通讯录同步 | 写同步脚本 + 增量处理 + 冲突处理 ≈ 5 人日 | 配置连接 + 连通测试 ≈ 半天 | | 企微安全登录 | OAuth + state 校验 + 票据交换 ≈ 3 人日 | 配置连接 + 能力绑定 ≈ 2 小时 | | 企微消息投递 | 企微 API + 逐人结果 + 重试 ≈ 3 人日 | 统一消息渠道,配置即用 | | 企微待办卡片 | 任务投影 + 回调 + 鉴权 ≈ 5 人日 | 绑定流程 + 安全跳转 | | 开放 API 网关 | 认证 + 防重放 + 限流 + 幂等 ≈ 8 人日 | 开启网关 + 注册能力 | | 客户端授权管理 | 凭据 + 授权 + 审计 ≈ 5 人日 | 控制台配置,开箱即用 | | 调用文档 | 手写文档 + 维护 ≈ 持续成本 | 自动生成 Markdown + OpenAPI | | 飞书/钉钉扩展 | 全部重来 ≈ 15+ 人日 | 实现 Connector,不改主链路 | **粗算:自己搭这套企业集成,40-50 人日起步。用 Forge,配置 + 验证,一周内能跑通。** --- ## 五、说点实在的不足 不吹,客观说几个当前的限制: 1. **飞书、钉钉适配器还没做。** 通用底座和合同测试已经就位,企微是第一个完整适配器,飞书/钉钉需要后续独立实现——但不用改主编排链路,这是架构上的保证。 2. **企微待办的"卡片内直批"默认关闭。** 基线只开放"安全跳转到 Forge 查看详情"。客户要启用卡片内同意/驳回,需要额外配置流程白名单和专项 UAT——这是安全取舍,不是技术做不到。 3. **需要公网 HTTPS 和企微可信域名。** 企微回调要求公网可达的 HTTPS 地址、可信域名/IP 白名单和稳定证书,本地开发需要用内网穿透工具。 4. **开放平台默认关闭。** `FORGE_CAPABILITY_OPEN_GATEWAY_ENABLED=false`,需要显式开启。这是安全设计——不用的能力默认不暴露。 5. **作为相对年轻的功能模块,** 企微集成的真实大规模 UAT 还在积累中。如果你的企业规模大(几千人以上),建议先在测试企业验证同步性能和回调量级。 --- ## 六、上手体验 所有文章里说的能力,演示站都可以在线试: - **后台管理演示**:http://www.dlforgelab.com:8084/forge/login (账号 `admin` / `123456`) - 企业协同:系统管理 → 企业协同 - 能力开放:开放平台 → 能力目录 / 客户端 / 授权管理 / 调用日志 - **项目文档**:http://www.dlforgelab.com:8084/forge-docs/ **源码地址:** - Gitee:https://gitee.com/ForgeLab/forge-admin - GitHub:https://github.com/yaomindong1996/forge-admin --- ## 七、最后聊两句 上篇"搭积木"聊的是怎么把**内部能力**做扎实。这篇聊的是怎么把这些能力**接通企业生态**——向内接企业微信,向外开能力网关。 企业后台说到底解决的是三件事:**内部管得好、对内能协同、对外能开放。** 缺一不可。 做企微集成时最深的感受是:**安全边界比功能更重要。** 登录不能信任前端身份、通讯录同步不能误删人员、待办回调不能越权审批——这些不是"做了就行",是"做对了才敢上"。所以你在文章里看到大量"失败关闭""禁止自动合并""重新校验"的设计,都是被真实场景教出来的。 做开放平台时最深的感受是:**管理员体验决定成败。** 网关安全做得再好,管理员配完不知道行不行、开发要翻日志排障,那这个平台就是半成品。所以调用指南、就绪诊断、在线测试、自动文档——这些"体验"功能花的精力不比安全链路少。 > 开源不易,持续迭代更难。如果觉得有用,点个 Star 是最大的鼓励。 **你现在的企业集成方案是什么?企微对接最头疼的是哪块?评论区聊聊,想看哪块源码拆解的也可以扣——** - **扣 1**:想看企微通讯录同步的源码拆解(全量快照 + 增量 + 冲突处理) - **扣 2**:想看开放网关安全链路的源码拆解(认证 → 防重放 → 授权 → 限流 → 幂等) - **扣 3**:想看 OAuth state + 一次性票据登录链路的完整拆解 我挑呼声最高的那块下一篇详细写。