corp-transfer/convert-wecom-ids-gk.README.md

282 lines
8.7 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
并把转换后的数据按 `_id` 回写到原 MongoDB collection。
安全说明:
- 默认 dry-run不写入任何 collection
- 只有 `--apply --yes` 才会写入
- `--apply` 会直接更新原 collection
- 回写时默认使用 **upsert**(按 `_id` 覆盖更新),因此报错后可直接重跑
---
## 依赖与运行方式
- Node.js建议 18+
- 依赖:`mongodb``axios`(项目内已安装)
在目录 `c:\code\yk\gykq\transfer` 下运行:
```powershell
cd c:\code\yk\gykq\transfer
node transfer.js --help
```
脚本支持读取 `.env``.env.<NODE_ENV>``env.<NODE_ENV>`。当前仓库已可直接使用 `.env.gk`
注:脚本文件为 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 做脱敏)。
---
## 典型用法
如果你已经准备好了 `.env.gk`,可直接运行:
```powershell
node transfer.js --apply --yes
```
执行 `npm run build` 后,`.env.gk` 会被内嵌进 `dist/transfer.js`,因此发布产物是单文件。若你修改了 `.env.gk`,需要重新构建一次。
### 1) dry-run推荐先跑
只扫描统计,不写入任何表:
```powershell
node transfer.js `
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" `
--dbName corp `
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA `
--skipApi
```
Linux / macOSbash/zsh
```bash
node transfer.js \
--mongoUri "mongodb://<user>:<pass>@<host>:27017/admin" \
--dbName corp \
--targetCorpId wpLgjyawAAeRkCPQMp9-z5q-xEzK64nA \
--skipApi
```
### 2) 实际回写原 collection
PowerShell
```powershell
$env:WECOM_SECRET='你的corpsecret'
node transfer.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 transfer.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 transfer.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 transfer.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 transfer.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 transfer.js \
--preset gk-suite \
--dumpScope --scopeOnly
```
检查某些 userid 是否在可见范围内:
```bash
node transfer.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也不写库可以用
```bash
node transfer.js \
--tokenMode corpSecret \
--tokenCorpId <corpId> \
--secret "<corpsecret>" \
--sourceAgentId 1000076 \
--openUserIds woXXXX,woYYYY \
--externalUserIds wmXXXX,wmYYYY
```
tokenMode=suite 也支持直接提供 token 所需参数(无需 Mongo
```bash
node transfer.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`:已不再支持;当前 apply 模式固定按 `_id` upsert 回写原表
- `--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 transfer.js --listPresets
node transfer.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 时需要
```