企业微信配置与集成机制¶
前端入口:
obpm-manager-vue3/src/components/weixin.vue
管理 API:obpm-manager/.../wechat/WechatAuthtimeController.java
核心服务:obpm-core/.../support/weixin/WeixinService.java、WeixinSecretCache、QyApiService
测试扫码:obpm-common/.../wecom/WeixinQrCodeTestSupport.java(内存 ticket,不登录)
扫码登录:obpm-signon/.../LoginController.java
OAuth SSO:obpm-runtime/.../RuntimeSecurityFilter+WeixinService.auth
接口明细另见 [[../../restful-api/manager/wechat-authtime]]、[[../../restful-api/signon/login]]
本文梳理管理台「企业微信」配置项,以及**通讯录同步、扫码登录、URL 跳转(OAuth)、消息推送**四条主流程在前后端中的工作机制。
1. 总览¶
企业管理中心在域(租户)维度绑定企业微信。启用后,平台用域级 CorpID / Secret 与各软件的 AgentId / Secret,调用企业微信开放接口完成组织同步、免登跳转与待办消息。
flowchart TB
subgraph UI["管理台 weixin.vue"]
CFG["域级配置(分组)<br/>CorpID / 通讯录Secret / 只读应用 / 扫码三项"]
APP["软件级 AgentId + Secret"]
ACT["保存 / 组内同步 / 测试扫码 / 生成跳转链接"]
end
subgraph Persist["持久化 T_DOMAIN"]
COL["WEIXIN_* 列 + WEIXIN_CONFIG JSON"]
end
subgraph Hub["运行时枢纽"]
CACHE["WeixinSecretCache"]
TOKEN["QyApiService.getAccessToken<br/>qyapi gettoken"]
end
subgraph Flows["业务能力"]
SYNC["通讯录双向同步"]
QR["PC 扫码登录"]
OAUTH["应用内 OAuth 跳转 / SSO"]
MSG["流程待办 / 图文 / 文本消息"]
end
CFG --> Persist
APP --> Persist
Persist --> CACHE
CACHE --> TOKEN
TOKEN --> SYNC & OAUTH & MSG
Persist --> QR
身份对齐约定(贯穿所有流程):
| OBPM | 企业微信 |
|---|---|
用户 loginno |
成员 userid |
部门 weixinDeptId |
部门 id |
OAuth / 消息 appid |
企业 CorpID(不是小程序 AppId) |
2. 前端页面与配置项¶
2.1 入口、布局与开关¶
| 项 | 说明 |
|---|---|
| 菜单位置 | 域管理 → 微信配置(Domain.vue 加载 weixin.vue) |
| 功能开关 | Constant.ts → Setup.domain.weixinConfig |
| 启用方式 | weixinProxyType:none(不启用)/ EnterpriseWeChat(企业微信) |
| 历史遗留 | 模板仍保留 cloud 云代理区块;当前单选仅暴露 none / EnterpriseWeChat。常量中还有旧值 local(企业号本地绑定),管理台 UI 已不再配置 |
页面布局(工具栏不随内容滚动):
- 顶部
.weixin-toolbar:header_item,固定不滚;按钮仅 保存。 - 下方
.weixin-scroll:分组表单与软件列表,独立overflow-y: auto。 - 父级
.weixinCon为纵向 flex(height: 100%,overflow: hidden)。
同步、测试扫码不在顶部工具栏,而在对应分组**内容区字段同一行/下一行**:
| 位置 | 按钮 |
|---|---|
| 双向同步(读/写)通讯录 | 验证链接、同步本地组织架构到企业微信、从企业微信同步组织架构本地 |
| 单向同步(读)通讯录 | 验证、从企业微信同步组织架构本地 |
| 扫码登录 | 测试扫码(弹窗出码,不登录系统) |
验证连接成功后只提示验证结果;通讯录同步仍在对应分组内操作。
分组标题左侧绿色竖线与标题文字垂直居中;必填红星只出现在文案**右侧**(require-asterisk-position="right")。
2.2 域级配置字段(wechatConfigs)¶
开启企业微信后,页面按能力分组(与钉钉配置页同一套 part / smallHeader 样式):
| 分组 | 前端字段 | 界面文案 | 落库 | 用途 |
|---|---|---|---|---|
| 启用企业微信 | weixinCorpID |
企业微信CorpID(必填) | WEIXIN_CORP_ID |
企业身份;OAuth appid、gettoken corpid |
| 启用企业微信 | serverHost |
外网访问系统地址 | SERVER_HOST |
OAuth redirect_uri 基址、消息跳转、验证可达性 |
| 启用企业微信 | weixinVerifyFileName |
企业微信认证文件 | WEIXIN_CONFIG.verifyFileName |
可信域名校验文件名;磁盘 {storageRoot}/weixin-verify/ |
| 双向同步(读/写)通讯录 | weixinCorpSecret |
通讯录Secret | WEIXIN_CORP_SECRET |
通讯录写权限 token;OBPM→微信写组织 |
| 双向同步(读/写)通讯录 | weixinSyncRwEnable |
开启 | WEIXIN_SYNC_RW_ENABLE |
是否启用该组能力 |
| 单向同步(读)通讯录 | weixinAgentId / weixinSecret |
应用AgentId(已开通通讯录权限) / 应用Secret | WEIXIN_CONFIG 保留键 EnterpriseWeChat |
微信→OBPM 读组织、同步读 token |
| 单向同步(读)通讯录 | weixinSyncReadEnable |
开启 | WEIXIN_SYNC_READ_ENABLE |
是否启用该组能力 |
| 扫码登录 | weixinQrCodeAgentId |
应用AgentId(已开通扫码登录权限) | WEIXIN_QRCODE_AGENTID |
PC 扫码登录应用 |
| 扫码登录 | weixinQrCodeSecret |
应用Secret | WEIXIN_QRCODE_SECRET |
扫码换 token |
| 扫码登录 | weixinQrCodeCallbackUrl |
扫码CallbackUrl | WEIXIN_QRCODE_CALLBACKURL |
正式扫码回调地址(测试扫码的 redirect_uri 取其协议+域名) |
| 扫码登录 | weixinQrCodeEnable |
开启 | WEIXIN_QRCODE_ENABLE |
是否启用扫码登录 |
另外:weixinProxyType 在「启用企业微信」分组标题旁单选(none / EnterpriseWeChat),列 WEIXIN_PROXY_TYPE。
表单校验:选中企业微信时,weixinCorpID 必填;某分组勾选「开启」后,该组字段必填(双向:通讯录 Secret;单向:AgentId+Secret;扫码:AgentId+Secret+CallbackUrl)。未开启的分组不校验。
未配置只读通讯录 AgentId/Secret 时,WeixinSecretCache.get(domainId, "EnterpriseWeChat") 仍回退到域下第一个已配软件级凭证(兼容旧数据)。
2.3 软件级配置(wechatConfigs.apps[])¶
域下已绑定软件列表,每项可编辑:
| 字段 | 说明 |
|---|---|
weixinAgentId |
企业微信自建应用 AgentId |
weixinSecret |
该应用 Secret(发消息、应用级 OAuth、JS-SDK) |
存储不在独立表,而在域字段 WEIXIN_CONFIG(JSON):
{
"weixinAgentId": {
"EnterpriseWeChat": "1000001",
"<applicationId>": "1000003"
},
"weixinSecret": {
"EnterpriseWeChat": "<contacts-read-secret>",
"<applicationId>": "<app-secret>"
},
"verifyFileName": "WW_verify_AIlEBTeMZWjzofq8.txt"
}
保留键 EnterpriseWeChat 表示域级「单向同步(读)通讯录」凭证,不是真实软件 id。软件级仍按 applicationId 存 AgentId/Secret。
对应 Java:WeixinConfig / DomainVO.getWeixinAgentId(appId) / setWeixinSecret(appId, secret)。
2.4 页面操作 ↔ API¶
| 操作 | 前端方法 | API(src/api.js) |
后端 |
|---|---|---|---|
| 加载配置 | created → getWechatConfig |
GET .../domain/{id}/wechat |
getWechatConfig |
| 保存域配置 | onSaveBtnClick |
PUT .../domain/{id}/wechat |
saveWechatConfig |
| 上传认证文件 | uploadVerifyFile |
POST .../wechat/verifyfile |
uploadWeixinVerifyFile |
| 验证连接 | onVerifyBtnClick |
GET .../wechat/corp/{corpid}/corpsecret/{corpsecret}?serverHost= |
validationExtranetAccessAddress |
| 验证只读通讯录 Secret | onVerifyReadSecret |
GET .../wechat/accesstoken?corpid=&corpsecret= |
verifyWechatAccessToken(gettoken 成功即通过,不返回 token) |
| 保存 AgentId | onSaveWeixinAgentId |
PUT .../updateWeixinAgentId?id= |
updateWeixinAgentId |
| 保存应用 Secret | onSaveWeixinSecret |
PUT .../updateWeixinSecret?secret= |
updateWeixinSecret |
| 生成跳转链接 | genWeChatURL |
GET .../getwechaturl |
getWechatUrl |
| 微信→OBPM 同步 | onSynFromWeixin |
PUT .../synchfromwechat |
synchFromWechat |
| OBPM→微信 同步 | onSync2Weixin |
PUT .../synch2wechat |
synch2Wechat |
| 测试扫码 | onTestQrCode |
POST .../wechat/qrcode/test + 轮询 GET .../qrcode/test/status |
startWechatQrCodeTest / getWechatQrCodeTestStatus;回调 GET .../qrcode/test/callback 匿名 |
基址:${manager-context}/api/authtime。
2.5 企业微信域名认证文件¶
企业微信校验可信域名时会请求站点根路径:
https://{host}/WW_verify_{token}.txt
实现:
- 管理台「启用企业微信」组上传
WW_verify_xxx.txt(文件名必须匹配^WW_verify_[A-Za-z0-9]+\.txt$,上限 16KB)。 - 文件写入
{storageRoot}/weixin-verify/{原文件名};文件名记入WEIXIN_CONFIG.verifyFileName。 WeixinDomainVerifyFilter(obpm-common,orderHIGHEST_PRECEDENCE+2)拦截 GET/HEAD,原样返回text/plain内容;未找到则 404。- 微服务下站点根路径由 Nginx 反代到 manager:
/WW_verify_*→{manager}/WW_verify_*(避免被静态location /吃掉)。lite 一体化且 context 为/时可直接由过滤器响应。
公开访问不走登录;上传接口需管理员鉴权。
3. 数据模型与凭证枢纽¶
3.1 主要表字段¶
T_DOMAIN(企业域)
| 列 | 含义 |
|---|---|
WEIXIN_PROXY_TYPE |
代理类型 |
WEIXIN_CORP_ID / WEIXIN_CORP_SECRET |
企业 ID / 通讯录 Secret |
SERVER_HOST |
公网基址 |
WEIXIN_QRCODE_* |
扫码登录三项 |
WEIXIN_SYNC_RW_ENABLE / WEIXIN_SYNC_READ_ENABLE / WEIXIN_QRCODE_ENABLE |
双向同步 / 单向同步 / 扫码登录开关(未落库时按对应 Secret 是否已填推断) |
WEIXIN_CONFIG |
按软件的 AgentId/Secret JSON |
WEIXIN_TOKEN / WEIXIN_ENCODING_AESKEY |
回调加解密(管理台本页未暴露,用于事件回调) |
WEIXIN_AGENT_ID |
旧版单应用 AgentId(兼容) |
实体:DomainVO(core)、DomainPO(usercenter)、signon.auth.model.Domain(扫码读同一列,字段名 weixinCorpId)。
T_DEPARTMENT
| 列 | 含义 |
|---|---|
WEIXIN_DEPT_ID |
与企业微信部门 id 的映射 |
3.2 WeixinSecret 与双 Secret 模型¶
运行时统一封装为 WeixinSecret:corpID、corpSecret、agentId、serverHost、token、encodingAESKey。
flowchart LR
D["DomainVO"] --> C1["WeixinSecretCache.get(domainId)<br/>CorpID + 通讯录Secret"]
D --> C2["WeixinSecretCache.get(domainId, appId)<br/>CorpID + 应用Secret + AgentId"]
C1 --> W["通讯录写 / 部分同步"]
C2 --> A["发消息 / OAuth / JS-SDK"]
C1 & C2 --> T["QyApiService.getAccessToken<br/>https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=&corpsecret="]
| 缓存取法 | Secret 来源 | 典型用途 |
|---|---|---|
get(domainId) |
weixinCorpSecret(通讯录) |
创建/更新微信侧部门与用户(写) |
get(domainId, "EnterpriseWeChat") |
WEIXIN_CONFIG 保留键 AgentId+Secret;若未配则回退第一个已配软件 |
双向/单向同步的**读** token |
get(domainId, applicationId) |
该软件 AgentId+Secret | 发消息 / OAuth / JS-SDK |
Token 内存缓存 key:corpid + corpsecret。配置变更后 saveWechatConfig 会 WeixinServiceProxy.cleanWeixinSecretCache()。
4. 配置保存与验证流程¶
sequenceDiagram
participant Page as weixin.vue
participant API as WechatAuthtimeController
participant Dom as DomainProcess / T_DOMAIN
participant Cache as WeixinSecretCache
participant WX as 企业微信 qyapi
Page->>API: GET /domain/{id}/wechat
API->>Dom: doView
API-->>Page: wechatConfigs + apps
Page->>API: GET .../corp/{corpid}/corpsecret/{secret}?serverHost=
API->>WX: gettoken(corpid, corpsecret)
API->>API: HTTP GET serverHost/.../static/mobile/index.html
API-->>Page: 验证成功 / 失败
Page->>API: PUT /domain/{id}/wechat (整包配置)
API->>Dom: setWeixin* + doCreateOrUpdate
API->>Cache: clear
API-->>Page: 保存成功
**验证连接**两步:
- 用页面上的 CorpID + 通讯录 Secret 换
access_token(可不先保存)。 - 探测
serverHost(兼容去掉/obpm)下移动端首页是否 HTTP 200。
5. 通讯录同步¶
入口按钮文案与方向:
| 按钮 | API | 实现 | 方向 |
|---|---|---|---|
| 从企业微信同步组织架构本地 | PUT .../synchfromwechat |
WeixinService.synchFromWeixin |
微信 → OBPM |
| 同步本地组织架构到企业微信 | PUT .../synch2wechat |
WeixinService.synch2Weixin |
OBPM → 微信 |
结果弹窗 weixin_result.vue 展示:DEPT_ADD_SUCCESS/FAIL、USER_ADD_SUCCESS/FAIL、ERRORS[]。
前置条件:License 检查(当前 validLicenseAuth() 恒为 true);企业微信侧有部门;EnterpriseWeChat 模式下通常还需至少一个软件已配 AgentId+Secret(读 token)。
5.1 微信 → OBPM(synchFromWeixin)¶
flowchart TD
A["取 access_token<br/>Cache.get(domainId, EnterpriseWeChat)"] --> B["QyApiService.getDepartmentList"]
B --> C["按 level 处理部门"]
C --> C1["根部门:更新本地域根名称 + weixinDeptId"]
C --> C2["子部门:按 weixinDeptId / 同名同层匹配或新建"]
C --> D["按部门拉取成员 getUsersByDepartment"]
D --> E{"loginno == wx.userid 是否存在?"}
E -->|否| F["新建 UserVO<br/>loginno=userid<br/>默认密码等"]
E -->|是| G["更新姓名/手机/邮箱/部门/扩展字段"]
F & G --> H["回写成功失败计数与 ERRORS"]
要点:
- 部门映射写入
DepartmentVO.weixinDeptId。 - 用户主键对齐:
User.userid→UserVO.loginno;新建时赋默认密码、标准日历、在职状态,可拉头像。 - 多部门成员会挂到多个本地部门;默认部门取同步遍历中的部门。
5.2 OBPM → 微信(synch2Weixin)¶
flowchart TD
A["读 token = get(domain, EnterpriseWeChat)<br/>写 token = get(domain) 通讯录Secret"] --> B["查询本地域有效部门 level 升序"]
B --> C["根部门:无则 createDepartment,有则 update"]
C --> D["子部门:按 weixinDeptId 更新或 create,回写 weixinDeptId"]
D --> E["遍历域用户 queryByDomain"]
E --> F{"微信是否已有 loginno?"}
F -->|有| G["字段有变更则 updateUser(写 token)"]
F -->|无| H{"在职且手机或邮箱非空?"}
H -->|是| I["createUser,userid=loginno"]
H -->|否| J["记入 ERRORS 跳过"]
要点:
- **读**用应用侧 token,**写**用通讯录 Secret(
modify_access_token)。 - 失效部门/用户、无手机且无邮箱的用户不同步创建。
- 日常在管理台改用户时,
UserAuthtimeController/UserUtil还会异步投递queue-user-weixin,调用createOrUpdateUser2Weixin做增量同步。
6. 扫码登录(PC)¶
与应用内 OAuth 是两条路径:扫码走 signon,配置使用 扫码专用 AgentId / Secret / CallbackUrl。
sequenceDiagram
participant Login as 登录页 signon-web
participant Signon as LoginController
participant DB as T_DOMAIN
participant WX as 企业微信
Login->>Signon: GET /api/runtime/login/getwxconfig?domainName=
Signon->>DB: 读 WEIXIN_CORP_ID / QRCODE_*
Signon-->>Login: appId=CorpID, agentId, callbackUrl
Login->>WX: 企业微信扫码组件(WwLogin 等)
WX->>Signon: GET /api/runtime/login/wxqrcodelogin?code=&state=
Note over Signon: state = contentPath@domainName
Signon->>WX: gettoken(CorpID, weixinQrCodeSecret)
Signon->>WX: getuserinfo → UserId
Signon->>DB: Account(username=UserId) + User(domain)
Signon-->>Login: Set-Cookie accessToken,跳转 dispatcher.html
| 步骤 | 说明 |
|---|---|
| 取配置 | appId = domain.weixinCorpId(即管理台 CorpID) |
| 换用户 | WeixinUtil.getAccessToken(corpId, weixinQrCodeSecret) + getUserId |
| 落本地用户 | Account.username / 域内用户需与企业微信 UserId(通常即 loginno)一致 |
| 回调 URL | 管理台配置的 weixinQrCodeCallbackUrl,需与企业微信应用可信域名一致 |
管理台占位示例:http://www.xxx.com/signon/runtime/login/wxqrcodelogin(部署时按实际 signon 上下文调整)。
6.1 管理台「测试扫码」¶
扫码登录分组**内容区**(CallbackUrl 下方)提供 测试扫码,用于验证 AgentId / Secret / 回调域是否可用,不会登录系统。顶部工具栏无此按钮。
sequenceDiagram
participant Page as weixin.vue
participant API as WechatAuthtimeController
participant Store as WeixinQrCodeTestSupport
participant WX as 企业微信 WwLogin
Page->>API: POST /domain/{id}/wechat/qrcode/test
API->>Store: 创建 ticket(5 分钟)
API-->>Page: appId / agentId / redirectUri / state=ticket
Page->>WX: WwLogin 弹出二维码
WX->>API: GET .../qrcode/test/callback?code=&state=ticket
Note over API: 匿名;redirect_uri 取 CallbackUrl 的协议+域名
API->>WX: gettoken(CorpID, weixinQrCodeSecret) + getuserinfo
API->>Store: ticket = success(UserId) / fail
Page->>API: 轮询 GET .../qrcode/test/status?ticket=
API-->>Page: pending / success / fail
要点:
- 弹窗用企业微信官方
WwLogin出码;扫完后 iframe 跳到测试回调页,管理台轮询(或postMessage)展示成功/失败。 redirect_uri必须落在应用「授权回调域」:从已保存的weixinQrCodeCallbackUrl取 host,拼{manager-context}/api/authtime/domain/{id}/wechat/qrcode/test/callback。本机 Vite(如 localhost:5174)若回调域不是该 host,扫码后企业微信无法打到当前 manager。- 回调匿名(
ManagerSecurityFilter放行该路径);开始/轮询接口仍需管理员登录。 - 成功时展示企业微信
UserId;非企业成员(仅OpenId)记为失败。
7. URL 跳转(应用内 OAuth / SSO)¶
用于:企业微信工作台「进入系统」、流程待办图文卡片、表单二维码在微信内打开等。
7.1 管理台「生成跳转链接」¶
getWechatUrl 拼装:
https://open.weixin.qq.com/connect/oauth2/authorize
?appid={weixinCorpID}
&redirect_uri={URLEncode(serverHost/obpm/api/sso?application=...&jumpTo=...)}
&response_type=code
&scope=snsapi_base
&agentid={软件 AgentId}
&state={domainId}
#wechat_redirect
- 普通软件:
jumpTo→/static/mobile/index.html#/?application={appId} - KM 特例:
application=km,跳 KMS 移动页
前端 weixinUrl.vue 展示可复制链接。
7.2 运行时免登链路¶
sequenceDiagram
participant User as 企业微信客户端
participant WX as open.weixin.qq.com
participant RT as Runtime /api/sso
participant Filter as RuntimeSecurityFilter
participant Auth as WeixinService.auth
participant QY as qyapi
User->>WX: 打开授权 URL
WX->>RT: redirect_uri?code=&state=domainId&application=
Filter->>Filter: URI 含 /sso 且带 code/state → 微信 OAuth
Filter->>Auth: WeixinServiceProxy.auth
Auth->>QY: gettoken(应用 Secret) + getuserinfo(code, agentId)
Auth->>Auth: loginno / 手机 / 邮箱 匹配 UserVO
Auth-->>Filter: accessToken + serverHost
Filter-->>User: 脚本跳转 jumpTo?accessToken=
关键实现:
RuntimeSecurityFilter:未登录且命中/sso+code+state时走微信 OAuth(实现里 User-Agent 判断写死为常量"MicroMessenger",实际以 URI/参数为准)。WeixinService.auth:state=域 id;用WeixinSecretCache.get(domainId, applicationId);UserId依次按 loginno → 手机 → 邮箱查找;签发 CookieaccessToken,返回token,serverHost。- Filter 拼
serverHost + jumpTo + accessToken完成落地页跳转。
7.3 其它拼装 OAuth URL 的位置¶
| 场景 | 代码 |
|---|---|
| 流程待办图文 | WeixinService.send → redirect 到 /obpm/api/sso?...&jumpTo=打开文档 |
| 关注企业号欢迎图 | EventCallbackService.handleSubscribeEvent |
| 表单二维码微信内打开 | QRCodeFiledScanEventReadyServlet.getWeiXinOAuthUrl |
共同点:appid 一律用 CorpID。
8. 发送消息¶
8.1 触发入口¶
| 入口 | 说明 |
|---|---|
| 流程通知 | Notification 注册 WeixinMode;待办等节点触发 WeixinMode.send → WeixinService.send |
| 脚本 / 工具 | MessageUtil.sendTextMessage / sendRichTextMessage / sendMessage |
| 关注/进入应用回调 | EventCallbackService 直接 MessageService.send |
8.2 待办图文消息流程¶
flowchart LR
N["流程 Notification"] --> M["WeixinMode"]
M --> S["WeixinService.send(title, desc, loginno, doc)"]
S --> C["WeixinSecretCache.get(domainId, applicationId)"]
S --> U["拼 OAuth 链接<br/>appid=CorpID → /obpm/api/sso → 打开表单"]
S --> Q["NewsMessage 入 JMS<br/>queue-message-weixin"]
Q --> H["WeixinMessageQueue.handle"]
H --> API["MessageService.send<br/>qyapi message/send"]
要点:
- 接收人:
touser= 用户loginno(企业微信 userid)。 agentid:来自该软件在WEIXIN_CONFIG中的 AgentId。- Token:该软件应用 Secret 换取。
- 异步:
WeixinMessageQueue监听queue-message-weixin,真正 POSThttps://qyapi.weixin.qq.com/cgi-bin/message/send。 - 用户增量同步走另一队列
queue-user-weixin。
8.3 其它消息类型¶
| 方法 | 类型 | 说明 |
|---|---|---|
send |
news | 待办:标题 + 摘要 + OAuth 深链 |
sendRichTextMessage |
news | 自定义 url/pic |
sendTextMessage |
text | 纯文本;pm/qm 等内置应用 id 有映射 |
sendMessage |
自定义 JSON | 按企业微信消息格式透传 |
均受 validLicenseAuth() 门控(当前恒 true)。
9. 相关能力(本页衍生)¶
| 能力 | 说明 |
|---|---|
| JS-SDK | Runtime WeixinServiceController → getJsapiConfig;appId=CorpID,ticket 按 CorpID 缓存 |
| 事件回调 | validWeixinUrl / handelWeixinCallbackEvent:用 WEIXIN_TOKEN + ENCODING_AESKEY + CorpID 做 WXBizMsgCrypt |
接口清单见 [[../../restful-api/manager/wechat-authtime]]。
10. 配置清单(落地检查)¶
在企业微信管理后台与 OBPM 管理台需对齐:
- CorpID →
weixinCorpID(必填) - 通讯录同步 Secret →
weixinCorpSecret(OBPM→微信写组织必备) - 只读通讯录应用 AgentId + Secret → 域级
weixinAgentId/weixinSecret(微信→OBPM 读组织;未配时回退软件级凭证) - 每个要进工作台/发消息的软件:自建应用 AgentId + Secret → 表格编辑
- 外网
serverHost:可被企业微信服务器与终端访问;OAuth 可信域名与之匹配 - 域名认证文件:在「启用企业微信」组上传企业微信下发的
WW_verify_xxx.txt,使https://{host}/WW_verify_xxx.txt可匿名访问 - 扫码登录应用(可选):开启后 AgentId / Secret / 回调 URL 必填;可用组内 测试扫码 验证(不登录)
- 用户对齐:
loginno与企业微信成员账号一致(或至少手机/邮箱能匹配 OAuth)
11. 实现备注(源码现状)¶
- 只读通讯录凭证:域级 AgentId/Secret 写入
WEIXIN_CONFIG保留键EnterpriseWeChat,与软件级配置共用 JSON,不新增表列。 - License:
validLicenseAuth()内写死true,原WarpProcessFactory.isWeixinEnable()已注释。 - 双 token 同步:
synch2Weixin读用只读通讯录(或回退软件)Secret、写用通讯录 Secret;通讯录 API 权限需在企业微信侧正确授权。 - 云代理 / local:代码与常量仍有残留,当前管理台主路径是
EnterpriseWeChat。 - 域名认证文件:上传接口写入存储目录;公开 GET 必须打到能读到该目录的服务(默认 Nginx 反代到 manager),不要只把文件拷到 Tomcat
ROOT。 - 分组开启开关:
WEIXIN_SYNC_RW_ENABLE/WEIXIN_SYNC_READ_ENABLE/WEIXIN_QRCODE_ENABLE。lite 的ddl-auto=none不会自动加列,需执行:
ALTER TABLE T_DOMAIN
ADD COLUMN WEIXIN_SYNC_RW_ENABLE BIT NULL,
ADD COLUMN WEIXIN_SYNC_READ_ENABLE BIT NULL,
ADD COLUMN WEIXIN_QRCODE_ENABLE BIT NULL;
isRequireWeixinAuth:User-Agent 写成字面量"MicroMessenger",未读请求头;实际依赖 URI/sso+code+state。- 页面滚动:工具栏与内容拆开(
.weixin-toolbar/.weixin-scroll),避免保存条随表单滚动消失。 - 测试扫码:
WeixinQrCodeTestSupport内存 ticket(约 5 分钟);回调路径由ManagerSecurityFilter匿名放行;正式登录仍走 signonwxqrcodelogin。
12. 源码索引¶
| 层级 | 路径 |
|---|---|
| 配置页 | web/obpm-manager-vue3/src/components/weixin.vue |
| 跳转结果 / 同步结果 | weixinUrl.vue、weixin_result.vue |
| 前端 API | web/obpm-manager-vue3/src/api.js(约 7.x 微信段,含 startWeixinQrCodeTest / getWeixinQrCodeTestStatus) |
| 管理控制器 | java/obpm-manager/.../wechat/WechatAuthtimeController.java |
| 测试扫码 ticket | java/obpm-common/.../support/wecom/WeixinQrCodeTestSupport.java |
| 测试扫码回调放行 | java/obpm-manager/.../filter/ManagerSecurityFilter.java(/wechat/qrcode/test/callback) |
| 认证文件过滤器 | java/obpm-common/.../web/WeixinDomainVerifyFilter.java、.../support/wecom/WeixinDomainVerifySupport.java |
| 域模型 / 按软件配置 | DomainVO、WeixinConfig、DomainPO |
| 凭证缓存 | WeixinSecretCache、WeixinSecret |
| 企业微信 HTTP | QyApiService、MessageService |
| 业务门面 | WeixinService、WeixinServiceProxy |
| 消息/用户队列 | WeixinMessageQueue、JmsConfig.QUEUE_*_WEIXIN |
| 流程通知 | Notification、WeixinMode |
| OAuth SSO | RuntimeSecurityFilter、WeixinService.auth |
| 扫码登录 | signon/.../LoginController(getwxconfig / wxqrcodelogin)、WeixinUtil |
| 表单二维码 | QRCodeFiledScanEventReadyServlet |