corp-transfer/convert-wecom-ids-gk.README.md
2026-03-13 17:07:27 +08:00

274 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# convert-wecom-ids-gk
把第三方应用获取的:
- `external_userid`(服务商 external_userid
- `open_userid`(密文 open_userid
转换为自建应用/企业内部可用的:
- `external_userid`(企业 external_userid
- `userid`(明文 userid
并把转换后的数据写入新的 MongoDB collection原名 + `-gk` 后缀,如 `corp-member-gk`)。
安全说明:
- 默认 dry-run不创建、不写入任何 collection
- 只有 `--apply --yes` 才会写入
- 永远不会更新原 collection只读原表
- 写入 `*-gk` 时默认使用 **upsert**(按 `_id` 覆盖更新),因此报错后可直接重跑,一般不需要删表
---
## 依赖与运行方式
- Node.js建议 18+
- 依赖:`mongodb``axios`(项目内已安装)
在目录 `c:\code\yk\ykt\ytk-customer-service` 下运行:
```powershell
cd c:\code\yk\ykt\ytk-customer-service
node scripts/convert-wecom-ids-gk.js --help
```
脚本不读取任何 `.env` 文件Mongo/企微参数全部通过命令行参数或环境变量提供。
注:脚本文件为 UTF-8 编码;在 Windows PowerShell 里如果直接 `Get-Content` 看到中文乱码,请用 `Get-Content -Encoding UTF8 scripts/convert-wecom-ids-gk.js` 查看。
---
## 企业微信接口(脚本内部调用)
- 获取 `access_token``/cgi-bin/gettoken`
- open_userid -> userid`/cgi-bin/batch/openuserid_to_userid`
- 服务商 external_userid -> 企业 external_userid`/cgi-bin/externalcontact/from_service_external_userid`
若遇到 `errcode=60020 not allow to access from your ip`,需要把运行机器出口 IP 加到企业微信白名单后再执行。
补充:文档里很多地址写成 `.../xxx?access_token=ACCESS_TOKEN`。脚本里使用 `axios``params` 传参,最终效果仍然是拼到 URL query string日志里会以 `fullUrl` 字段打印出来,并对 token 做脱敏)。
---
## 典型用法
### 1) dry-run推荐先跑
只扫描统计,不写入任何 `*-gk` 表:
```powershell
node scripts/convert-wecom-ids-gk.js `
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" `
--dbName corp `
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA `
--skipApi
```
Linux / macOSbash/zsh
```bash
node scripts/convert-wecom-ids-gk.js \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--skipApi
```
### 2) 实际写入 `*-gk`(只新增,不改原表)
PowerShell
```powershell
$env:WECOM_SECRET='你的corpsecret'
node scripts/convert-wecom-ids-gk.js `
--apply --yes `
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" `
--dbName corp `
--collections wechat-friends `
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA `
--sourceAgentId 1000076
```
Linux / macOSbash/zsh
```bash
export WECOM_SECRET='你的corpsecret'
node scripts/convert-wecom-ids-gk.js \
--apply --yes \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--collections wechat-friends \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--sourceAgentId 1000076
```
### 3) 只跑指定 collection便于测试
```bash
node scripts/convert-wecom-ids-gk.js \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--collections wechat-friends,corp-member \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--skipApi
```
### 4) wechat 表数据太多:只跑一部分
只跑 `wechat-friends` 前 1000 条(默认按 `_id` 升序,便于稳定分段):
```bash
node scripts/convert-wecom-ids-gk.js \
--apply --yes \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--collections wechat-friends \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--limitDocs 1000
```
分段跑下一段(跳过前 1000 条,再跑 1000 条):
```bash
node scripts/convert-wecom-ids-gk.js \
--apply --yes \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--collections wechat-friends \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--skipDocs 1000 \
--limitDocs 1000
```
---
## 可见范围/成员列表排查(推荐)
当你发现 `open_userid -> userid` 大面积 `invalid_open_userid_list` 时,最常见原因不是“参数写错”,而是:当前 `access_token` 所代表的应用,在通讯录侧可见的成员范围很小(可见范围/权限交集)。
脚本提供 `--dumpScope`,会调用:
- `agent/get`:查看应用的 allow_user/allow_party/allow_tag
- `user/list_id`(文档 path=96067拉取“当前 token 可见的成员 userid 列表”
只做排查、不跑转换:
```bash
node scripts/convert-wecom-ids-gk.js \
--preset gk-suite \
--dumpScope --scopeOnly
```
检查某些 userid 是否在可见范围内:
```bash
node scripts/convert-wecom-ids-gk.js \
--preset gk-suite \
--dumpScope --scopeOnly \
--checkUserIds 23090101,23090102
```
## 参数说明
### MongoDB任选一种方式
- `--mongoUri "<mongodb uri>"`(或别名 `--mongoUrl "<mongodb uri>"`
- 或拆分参数(也支持对应环境变量兜底):
- `--mongoHost`(或 `MONGO_HOST` / `CONFIG_DB_HOST`
- `--mongoPort`(或 `MONGO_PORT` / `CONFIG_DB_PORT`,默认 `27017`
- `--mongoUser`(或 `MONGO_USER` / `CONFIG_DB_USERNAME`
- `--mongoPass`(或 `MONGO_PASS` / `CONFIG_DB_PASSWORD`
- `--mongoAuthDb`(或 `MONGO_AUTH_DB`,默认 `admin`
### 必填/常用
- `--dbName <db>`:只处理单个数据库(例如 `corp`;注意这是“数据库名”,不是 collection 名)
- `--targetCorpId <corpId>`:目标机构 corpId
- `--collections a,b,c`:只处理指定 collection可选例如 `corp-member,wechat-friends`;不传则扫描该库所有 collection
### 指定 ID 转换(不跑数据库)
如果你只想把指定的 `open_userid`/`external_userid` 转换出来用于验证(不扫描 Mongo也不写入 `*-gk`),可以用:
```bash
node scripts/convert-wecom-ids-gk.js \
--tokenMode corpSecret \
--tokenCorpId <corpId> \
--secret "<corpsecret>" \
--sourceAgentId 1000076 \
--openUserIds woXXXX,woYYYY \
--externalUserIds wmXXXX,wmYYYY
```
tokenMode=suite 也支持直接提供 token 所需参数(无需 Mongo
```bash
node scripts/convert-wecom-ids-gk.js \
--tokenMode suite \
--suiteAccessToken "<suite_access_token>" \
--permanentCode "<permanent_code>" \
--targetCorpId <auth_corpid> \
--sourceAgentId 1000076 \
--openUserIds woXXXX
```
### 只跑部分数据(单表分段)
- `--limitDocs <n>`:每个 collection 最多处理 n 条
- `--skipDocs <n>`:每个 collection 跳过前 n 条
- `--noSortById`:不按 `_id` 排序(默认按 `_id` 升序,分段更稳定)
### 企微转换相关(`--skipApi` 关闭时需要)
- access_token 获取方式2 选 1
- `--tokenMode suite`(推荐):使用第三方应用的 suite_token + 目标机构 permanent_code 获取该机构的 corp access_token
- 依赖MongoDB 的 `corp.weComToken(type=suiteToken).suite_token`、以及 `corp.corp.permanent_code`
- 无需传 `--tokenCorpId/--secret`
- `--tokenMode corpSecret`(默认):使用 `gettoken`(仅适用于自建应用/企业内部应用场景)
- `--tokenCorpId <corpId>`:用于 `gettoken` 的 corpId
- `--secret <corpsecret>`corpsecret
- `--secretEnv <ENV_NAME>`:从环境变量读取 corpsecret推荐
- `--sourceAgentId <agentid>`:第三方应用的 `source_agentid`
- 不传时脚本会尝试从 `corp` collection 的 `auth_info.agent[0].agentid` 推断(推断不到会报错)
### 写入与安全开关
- `--apply`:执行写入(不传则 dry-run
- `--yes``--apply` 时必须显式确认(避免误操作)
- `--insertOnly`:仅使用 `insertMany`(不建议;报错重跑容易重复插入或因重复 `_id` 报错)
- `--skipApi`:只扫描统计,不调企业微信接口(仅 dry-run 可用)
### 扫描/性能参数(可选)
- `--corpIdFields corpId,corpid,corp_id`:用于判断该 collection 是否属于目标 corp
- `--batchDocs 200`Mongo 游标批大小
- `--batchOpenIds 100``open_userid` 批量转换每次请求数量
- `--concurrencyExternal 8`external_userid 单条转换并发数
- `--aggressive`:更激进地识别字段/字符串(可能增加 API 调用量)
### 企微接口日志
- 默认会输出每一次企微接口调用的完整响应(成功/失败都会输出)
- 如需关闭:`--noWecomDebug`
---
## 预设(减少命令行参数)
脚本内置了少量预设(不包含任何明文账号/密码/secret用法
```bash
node scripts/convert-wecom-ids-gk.js --listPresets
node scripts/convert-wecom-ids-gk.js --preset gk-suite --collections wechat-friends --limitDocs 200 --apply --yes
```
建议在 Linux 上把敏感信息放环境变量里:
```bash
export GK_MONGO_URI='mongodb://<user>:<pass>@<host>:27017/admin'
export GK_CORP_SECRET='你的corpsecret' # 仅 tokenMode=corpSecret 时需要
```