@oj-module/cli 0.2.66 → 0.2.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/.oj-version +1 -0
- package/bin/oj +4 -0
- package/devkit/README.md +15 -7
- package/devkit/SKILL.md +30 -1
- package/devkit/framework-dev.md +10 -4
- package/devkit/manual.md +38 -12
- package/devkit/publish-walkthrough.md +110 -37
- package/devkit/wecom-internal-app.md +7 -2
- package/devkit/wecom-multi-corp-links.md +163 -0
- package/package.json +2 -2
- package/shell-dist/assets/{index.i0kqbxp050.js → index.6alqyx6ae0.js} +21 -1
- package/shell-dist/assets/{runtime.1xfsxcajj0.js → runtime.2dgstpjsu0.js} +3449 -3449
- package/shell-dist/index.html +4 -4
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/publish-keygen.test.ts +157 -0
- package/src/__tests__/templates-migration-schema-parity.test.ts +540 -0
- package/src/__tests__/templates-schema-columns.test.ts +15 -2
- package/src/__tests__/templates-tenant-scope.test.ts +6 -2
- package/src/bundle.ts +8 -3
- package/src/cli.ts +17 -5
- package/src/dev.ts +15 -10
- package/src/install.ts +11 -4
- package/src/keygen.ts +54 -0
- package/src/lifecycle/__tests__/bundle.test.ts +21 -3
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +1 -1
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +2 -2
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +5 -2
- package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +1 -1
- package/src/lifecycle/__tests__/manifest-contract.test.ts +75 -3
- package/src/lifecycle/__tests__/smoke.test.ts +2 -2
- package/src/manifest-contract.ts +91 -8
- package/src/market/bootstrap.ts +26 -2
- package/src/market/command.ts +1 -0
- package/src/market/publish.ts +5 -1
- package/src/market/walkthrough.ts +24 -8
- package/src/site.ts +2 -0
- package/src/usage.ts +8 -4
- package/src/vendor.ts +5 -1
- package/templates/config.yaml +4 -2
- package/templates/init.include.yaml +8 -3
- package/templates/openapi.json +460 -1
- package/templates/src/app/api/_platform/_lifecycle/compensate.ts +136 -0
- package/templates/src/app/api/_platform/_lifecycle/installer.ts +71 -22
- package/templates/src/app/api/_platform/_lifecycle/lock.ts +23 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/deploy-web.ts +28 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/preflight.ts +46 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/reload.ts +100 -36
- package/templates/src/app/api/_platform/_lifecycle/steps/smoke.ts +7 -15
- package/templates/src/app/api/_platform/_lifecycle/text-edit.ts +71 -19
- package/templates/src/app/api/_platform/_lifecycle/types.ts +26 -2
- package/templates/src/app/api/_platform/_lifecycle/uninstall.ts +93 -14
- package/templates/src/app/api/_platform/_shared/service/domain/settings.ts +8 -4
- package/templates/src/app/api/_platform/manifest.yaml +1 -0
- package/templates/src/app/api/_platform/market/api.ts +235 -10
- package/templates/src/app/api/_platform/migrations/0001__baseline.mysql.sql +178 -0
- package/templates/src/app/api/_platform/migrations/0001__baseline.pg.sql +173 -0
- package/templates/src/app/api/_platform/migrations/0001__baseline.sql +188 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.mysql.sql +17 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.pg.sql +16 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.sql +33 -0
- package/templates/src/app/api/_platform/schema.yaml +18 -0
- package/templates/src/app/api/_platform/seed.mysql.sql +10 -0
- package/templates/src/app/api/_platform/seed.pg.sql +10 -0
- package/templates/src/app/api/auth/_shared/wecom/client.ts +24 -4
- package/templates/src/app/api/home/migrations/0001__create_home_tables.mysql.sql +14 -0
- package/templates/src/app/api/home/migrations/0001__create_home_tables.pg.sql +14 -0
- package/templates/src/app/api/home/migrations/0002__tenant.pg.sql +4 -0
- package/templates/src/app/api/home/seed.mysql.sql +71 -0
- package/templates/src/app/api/home/seed.pg.sql +71 -0
- package/templates/src/app/api/notification/_shared/notify.ts +6 -6
- package/templates/src/app/api/notification/migrations/0001__create_notifications.mysql.sql +11 -0
- package/templates/src/app/api/notification/migrations/0001__create_notifications.pg.sql +11 -0
- package/templates/src/app/api/notification/migrations/0002__notifications_user.mysql.sql +8 -0
- package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.mysql.sql +21 -0
- package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.pg.sql +22 -0
- package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.mysql.sql +10 -0
- package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.pg.sql +11 -0
- package/templates/src/app/api/notification/migrations/0005__tenant.pg.sql +6 -0
- package/templates/src/app/api/notification/seed.mysql.sql +8 -0
- package/templates/src/app/api/notification/seed.pg.sql +11 -0
- package/templates/src/app/api/publish/_shared/identity.ts +69 -0
- package/templates/src/app/api/publish/api.ts +349 -0
- package/templates/src/app/api/publish/manifest.yaml +8 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.mysql.sql +23 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.pg.sql +23 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.sql +39 -0
- package/templates/src/app/api/publish/schema.yaml +33 -0
- package/templates/src/app/api/system/login-methods/api.ts +2 -1
- package/templates/src/app/web/_platform/__client/api.schemas.ts +15 -0
- package/templates/src/app/web/_platform/__client/index.ts +25 -1
- package/templates/src/app/web/entry.ts +9 -5
- package/templates/src/app/web/home/routes.ts +5 -0
- package/templates/src/app/web/login/locales/en-US.json +7 -1
- package/templates/src/app/web/login/locales/zh-CN.json +7 -1
- package/templates/src/app/web/login/pages/login.tsx +79 -86
- package/templates/src/app/web/login/routes.ts +54 -1
- package/templates/src/app/web/personal-center/locales/en-US.json +1 -0
- package/templates/src/app/web/personal-center/locales/zh-CN.json +1 -0
- package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +5 -0
- package/templates/src/app/web/system/__client/api.schemas.ts +2 -1
- package/templates/src/app/web/system/locales/en-US.json +1 -8
- package/templates/src/app/web/system/locales/zh-CN.json +1 -8
- package/templates/src/app/web/system/pages/settings/index.tsx +17 -4
- package/templates/src/app/web/system/routes.ts +0 -6
- package/templates/src/oj-market/web/__tests__/CardGrid.test.tsx +33 -0
- package/templates/src/oj-market/web/__tests__/DetailDrawer.test.tsx +69 -0
- package/templates/src/oj-market/web/__tests__/marketClient.fake.ts +7 -1
- package/templates/src/oj-market/web/api/client.ts +3 -0
- package/templates/src/oj-market/web/api/defaultClient.ts +5 -0
- package/templates/src/oj-market/web/components/CardItem.tsx +44 -1
- package/templates/src/oj-market/web/components/DetailDrawer.tsx +17 -1
- package/templates/src/oj-market/web/entry.ts +31 -2
- package/templates/src/oj-market/web/locales/en-US.json +5 -1
- package/templates/src/oj-market/web/locales/zh-CN.json +5 -1
- package/templates/src/oj-market/web/publish/__client/api.schemas.ts +61 -0
- package/templates/src/oj-market/web/publish/__client/index.ts +164 -0
- package/templates/src/oj-market/web/publish/locales/en-US.json +80 -0
- package/templates/src/oj-market/web/publish/locales/zh-CN.json +80 -0
- package/templates/src/oj-market/web/publish/pages/history.tsx +112 -0
- package/templates/src/oj-market/web/publish/pages/index.tsx +196 -0
- package/templates/src/oj-market/web/publish/pages/model.ts +52 -0
- package/templates/src/oj-market/web/publish/pages/token-modal.tsx +82 -0
- package/templates/src/oj-market/web/publish/routes.ts +41 -0
- package/templates/src/oj-market/web/types.ts +30 -0
- package/templates/tests/lifecycle/compensate.spec.ts +207 -0
- package/templates/tests/lifecycle/deploy-smoke.spec.ts +38 -14
- package/templates/tests/lifecycle/installer.spec.ts +28 -9
- package/templates/tests/lifecycle/market-api.spec.ts +164 -12
- package/templates/tests/lifecycle/preflight.spec.ts +68 -0
- package/templates/tests/lifecycle/role-title-translate.spec.ts +2 -32
- package/templates/tests/lifecycle/text-edit.spec.ts +45 -27
- package/templates/tests/lifecycle/uninstall.spec.ts +36 -0
- package/templates/tests/publish-credential.spec.ts +354 -0
- package/templates/tests/publish-identity.spec.ts +44 -0
- package/templates/tests/wecom-client-timeout.spec.ts +33 -3
- package/templates/tests/wecom-landing.spec.ts +63 -1
- package/templates/tsconfig.paths.json +1 -0
- package/templates/web.config.ts +6 -4
- package/vendor/host-versions.json +3 -3
- package/templates/seed.mysql.sql +0 -6
- package/templates/seed.pg.sql +0 -6
- package/templates/src/app/api/_platform/migrations/0001__create_users.mysql.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0001__create_users.pg.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0001__create_users.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.mysql.sql +0 -5
- package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.sql +0 -5
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.mysql.sql +0 -70
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.pg.sql +0 -67
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.sql +0 -67
- package/templates/src/app/api/_platform/migrations/0005__users_must_change.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0005__users_must_change.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0007__users_email.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.mysql.sql +0 -10
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.pg.sql +0 -10
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.sql +0 -11
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.mysql.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.pg.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.sql +0 -13
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.mysql.sql +0 -17
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.pg.sql +0 -16
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.sql +0 -18
- package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.mysql.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0012__market_history.mysql.sql +0 -13
- package/templates/src/app/api/_platform/migrations/0012__market_history.pg.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0012__market_history.sql +0 -14
- package/templates/src/app/api/_platform/migrations/0013__users_profile.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.mysql.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.pg.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.sql +0 -8
- package/templates/src/app/api/_platform/migrations/0015__tenant.mysql.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0015__tenant.pg.sql +0 -11
- package/templates/src/app/api/_platform/migrations/0015__tenant.sql +0 -44
- package/templates/src/app/api/_platform/migrations/0016__org.mysql.sql +0 -41
- package/templates/src/app/api/_platform/migrations/0016__org.pg.sql +0 -40
- package/templates/src/app/api/_platform/migrations/0016__org.sql +0 -62
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +0 -8
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +0 -8
- package/templates/src/app/web/system/pages/login-methods/index.tsx +0 -30
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 多企业专属登录链接运维清单
|
|
3
|
+
audience: 平台运维 / 服务商运营 / 企业管理员
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 多企业专属登录链接运维清单
|
|
7
|
+
|
|
8
|
+
> 适用:**一套部署服务 N 家企业**(代开发模板),每家企业用自己的专属链接进入。
|
|
9
|
+
> 本方案**不需要业务工程改代码**:所有动作都在企微后台与本站管理面完成;
|
|
10
|
+
> 宿主早跳透传 `corp` / `agent` 的修复在框架侧(`@oj-module/cli` 的 shell,见 §0)。
|
|
11
|
+
> 所有 URL / 参数按本表逐字填,不要 URL 编码、不要加空格。
|
|
12
|
+
>
|
|
13
|
+
> 当前部署基线(下称 `<站点>` = `https://exp.wiz.top`):
|
|
14
|
+
> 模板回调 `<站点>/api/auth/wecom/event`,授权回调域与可信域名均为 `exp.wiz.top`,
|
|
15
|
+
> `wecom_base_url = <站点>/api/auth/wecom`,网页授权 `redirect_uri = <站点>/api/auth/wecom/callback`(后端自动派生,不用手填)。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 0. 先读:能做什么
|
|
20
|
+
|
|
21
|
+
| 入口 | 是否可用 | 行为 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| 外部浏览器 / 企微会话消息 / 邮件 / 公告里的**专属链接** | ✅ 完整可用(实测) | 点开自动跳**该企业**的 `qrConnect` 扫码页 → 企微 App 扫码 → 回跳换票 → 首页 |
|
|
24
|
+
| 登录页「其他企业」折叠里手填企业代码 | ✅ 可用 | 等价于专属链接,适合链接丢失时兜底 |
|
|
25
|
+
| 企微工作台**应用主页** | ✅ 可用(需含修复版 shell 的 cli) | 宿主 P0 早跳把 `?corp=` / `?agent=` 白名单透传到 `/auth/wecom/login`;每家企业把应用主页填成自己的专属链接即可,企微内静默授权、零点击 |
|
|
26
|
+
|
|
27
|
+
因此:**每家企业发一条专属链接**,员工从专属链接进入,企微工作台应用主页也填各自的专属链接。
|
|
28
|
+
|
|
29
|
+
> 宿主早跳此前会丢掉 `?corp=`(只服务本企业),已修复:
|
|
30
|
+
> `packages/cli/shell/scripts/build.mts` 的 BOOT_JS 与 `shell/src/host.tsx` 的 P0 早跳
|
|
31
|
+
> 均按白名单 `corp` / `agent` 透传,票据 / `redirect` / `error` 一律不带。
|
|
32
|
+
> **部署侧必须重新构建 cli 的 shell-dist 并 `ojm build`**;仍用旧版 cli 的话,
|
|
33
|
+
> 外企业员工从工作台进入会被 `corpSelf()` 吸到本企业(或报「已授权多家企业」)。
|
|
34
|
+
|
|
35
|
+
> 为什么能一套部署服务多家:`wecom_app_profile` 主键含 `(corp_id, agent_id, suite_id)`,
|
|
36
|
+
> 每家企业授权后由 `create_auth` 自动落行;租户键 = `corp_id`,回跳 URL 带 `tenant`,
|
|
37
|
+
> 数据按租户列隔离;JIT 建档用户名 `wecom:<userid>`,跨企业不冲突。
|
|
38
|
+
> `qrConnect` 的 `appid` / `agentid` 是按 `corp` 从档案表查出来的,**不是写死**——
|
|
39
|
+
> 带 `?corp=A` 就跳 A 企业的授权页,带不存在的 `corp` 直接 400。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 1. 前置检查(一次性,平台侧)
|
|
44
|
+
|
|
45
|
+
| # | 项 | 期望值 / 检查方法 | 不通过的后果 |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| 1 | 代开发模板凭据 | `config.yaml` 的 `wecom_suite_id` / `wecom_suite_secret` / `wecom_callback_token` / `wecom_encoding_aes_key` / `wecom_enc_key` / `wecom_base_url` / `wecom_provider_id` / `wecom_provider_secret` 八项齐 | 服务起不来或换不出套件 token |
|
|
48
|
+
| 2 | 模板**指令回调 URL** | 服务商后台 → 模板 → 回调 URL:`<站点>/api/auth/wecom/event`(逐字;保存时企微会 GET 一次带 `echostr`,必须当次通过) | `suite_ticket` 收不到 → 后续所有授权全断 |
|
|
49
|
+
| 3 | 模板**可信域名** | `exp.wiz.top`(纯域名),按企微要求上传校验文件到域名根路径 | 授权页报 `redirect_uri 需使用应用可信域名` |
|
|
50
|
+
| 4 | 模板**授权完成回调域名**(有的版本叫「授权回调域」) | `exp.wiz.top` —— **纯域名,不带 `https://`、不带路径、不带端口、不带尾斜杠** | 外部浏览器扫码报 `redirect_uri 与配置的授权完成回调域名不一致` |
|
|
51
|
+
| 5 | 组织架构四项权限 + 成员授权模式 | 见 `wecom-daikaifa.md` §2.5 / §2.6 | 通讯录同步 `60011` / `48002` |
|
|
52
|
+
| 6 | 登录方式开关 | `/system/settings` → 启用企业微信登录;`curl <站点>/api/system/login-methods` 返回含 `wecom` | 登录页看不到「企业微信」页签 |
|
|
53
|
+
| 7 | 运营账号 | 能登 `/system/wecom` 的 **`superadmin`**(注意 `admin` 不是 superadmin) | 生成不了开通链接 |
|
|
54
|
+
|
|
55
|
+
> 第 3、4 项是**两处独立配置**:可信域名给企微客户端内的 `snsapi_base` 静默授权用,
|
|
56
|
+
> 授权完成回调域名给外部浏览器的 `qrConnect` 扫码用。工作台能登录只说明前者已配好。
|
|
57
|
+
> 用**自建应用**接 N 家企业时这两项要每家各配一遍;走**代开发模板**只需在模板上配一次,
|
|
58
|
+
> 所有企业共用——这正是多企业必须走代开发的原因(`wecom-internal-app.md` §1.1)。
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 2. 每家企业接入(逐家执行)
|
|
63
|
+
|
|
64
|
+
1. `superadmin` 登 `<站点>/system/wecom` → 代开发卡片 → 点「**生成开通链接**」
|
|
65
|
+
(每次点都重新向企微换,链接有效期以企微返回为准,不要缓存;可选 `state=prod` 指定环境标签)。
|
|
66
|
+
2. 把链接 / 二维码发给**该企业管理员**(只有企业管理员能授权)。
|
|
67
|
+
3. 管理员扫码或打开链接完成授权 → 企微推 `create_auth` → 本站自动完成:
|
|
68
|
+
- 按 `agentIds` 逐个写 `wecom_app_profile`(**同一企业多个应用各一行**);
|
|
69
|
+
- 建租户(键 = `corp_id`);
|
|
70
|
+
- 建该租户管理员 `admin`(`provisionTenantAdmin`,尽力而为,失败可补)。
|
|
71
|
+
4. 回到 `/system/wecom` 清单确认该企业出现、`status=active`,**记下 `corp_id` 与 `agent_id`**。
|
|
72
|
+
- `corp_id` 是 `ww` 开头的**真实企业 ID**;不要抄成企微后台的 `open_corpid`。
|
|
73
|
+
- 从清单页复制,不要凭记忆手打;也可查库 `select corp_id, agent_id from wecom_app_profile where status='active'`。
|
|
74
|
+
5. 同页「**重设租户管理员口令**」给该企业设初始口令(落库只有 bcrypt,置 `must_change=1`,首次登录必须改)。
|
|
75
|
+
把「**企业代码 + 初始口令**」交给该企业管理员。
|
|
76
|
+
6. 按 §3 生成专属链接,发给该企业(公告 / 入职通知 / 会话消息 / 应用主页均可,但见 §0 边界)。
|
|
77
|
+
|
|
78
|
+
> 新增企业**不需要改配置、不需要重启**。停用企业在清单里点「停用」,会级联吊销该租户会话。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 3. 生成专属链接
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
<站点>/login?corp=<corp_id>&agent=<agent_id>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
示例(本企业自建应用):
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
https://exp.wiz.top/login?corp=wwd2d00dedd5c84818&agent=1000051
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| 参数 | 必填 | 从哪来 | 说明 |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| `corp` | **是** | `/system/wecom` 清单的 `corp_id` | 决定落在哪个租户、`qrConnect` 的 `appid` 用谁。填错 → `400 企业代码无效或应用未开通` |
|
|
97
|
+
| `agent` | **建议必填** | 同清单的 `agent_id` | 同企业装了多个应用时,不填会 `400 该企业开通了多个应用,登录链接必须带 agent 参数` |
|
|
98
|
+
| `redirect` | 否 | 站内路径 | 登录后跳到指定页;只放行 `/` 开头,拒绝 `//` 协议相对地址,非法值回落首页 |
|
|
99
|
+
| `tenant` | **不要填** | — | 由服务端 302 回跳时带,前端据此注入 `X-TENANT-ID`;手填会与票据租户冲突 |
|
|
100
|
+
|
|
101
|
+
三条红线:
|
|
102
|
+
|
|
103
|
+
- 链接里**只放 `corp` / `agent`**,绝不放 `access_token`、`wecom_ticket` 或任何票据。
|
|
104
|
+
一次性票据由后端 302 生成、180 秒有效、单次消费,用完即废。
|
|
105
|
+
- `corp` 不是机密(企业代码本就公开),但**别把 A 企业的链接发给 B 企业**——登录会落进 A 的租户。
|
|
106
|
+
- 逐字填写,不要 URL 编码、不要加空格、不要带尾斜杠。
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 4. 员工入口
|
|
111
|
+
|
|
112
|
+
| 入口 | 位置 / 链接 | 行为 |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| A 专属链接 | §3 的链接 | 自动发起授权:外部浏览器 → 企微 `qrConnect` 扫码页;企微内 → `snsapi_base` 静默。扫码 / 静默后回跳换票 → 首页 |
|
|
115
|
+
| B 登录页手填 | `<站点>/login` → 「企业微信」页签 →「其他企业?使用企业代码登录」 | 填 `corp` / `agent` 后跳;链接丢失时兜底 |
|
|
116
|
+
| C 不带参数的一键按钮 | `<站点>/login` 默认「使用企业微信一键登录」 | **只应给本企业用**:不带 `corp` 时后端 `corpSelf()` 从 `wecom_corp_*` 锁定本企业 |
|
|
117
|
+
| D 企微工作台应用主页 | 每家填自己的专属链接(§3) | 企微内 `snsapi_base` 静默授权、零点击;宿主早跳透传 `corp` / `agent` 落到正确企业 |
|
|
118
|
+
|
|
119
|
+
> 扫码那一步是企微在外部浏览器确认身份的动作,省不掉;本方案省的是「输账号密码 / 填企业代码 / 选页签」。
|
|
120
|
+
> 企微工作台内本来就是零点击静默,见 §0 边界。
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 5. 验收(每家企业逐项打勾)
|
|
125
|
+
|
|
126
|
+
- [ ] `/system/wecom` 清单出现该企业,`status=active`,`corp_id` / `agent_id` 已记录
|
|
127
|
+
- [ ] 拼链接自检(把 `<corp>` / `<agent>` 换成实际值):
|
|
128
|
+
`curl -s -D - -o /dev/null '<站点>/api/auth/wecom/login?corp=<corp>&agent=<agent>' -A 'Mozilla/5.0 Chrome/130'`
|
|
129
|
+
→ `302` 的 `location` 里 `appid=<该企业 corp_id>`、`agentid=<agent>`、
|
|
130
|
+
`redirect_uri` 指向 `<站点>/api/auth/wecom/callback`
|
|
131
|
+
- [ ] 外部浏览器打开专属链接 → 出现「请使用企业微信扫描二维码登录 <企业名>」,
|
|
132
|
+
**不是** `redirect_uri 与配置的授权完成回调域名不一致`
|
|
133
|
+
- [ ] 企微 App 扫码确认 → 落到 `<站点>/home`,地址栏里 **没有** `wecom_ticket`
|
|
134
|
+
- [ ] 该企业 `admin` 用初始口令登录 → 强制改密 → 能进管理面,看不到别家企业的数据
|
|
135
|
+
- [ ] `GET <站点>/api/system/login-methods` 返回含 `wecom`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 6. 故障速查
|
|
140
|
+
|
|
141
|
+
| 现象 / 文案 | 原因 | 处理 |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `redirect_uri 与配置的授权完成回调域名不一致` | 模板「授权完成回调域名」没填 `exp.wiz.top`,或填成了完整 URL / 带路径 | 改成纯域名,等几分钟生效(§1 第 4 项) |
|
|
144
|
+
| `redirect_uri 需使用应用可信域名` | 模板可信域名未备案 / 校验文件没传 | §1 第 3 项 |
|
|
145
|
+
| `企业代码无效或应用未开通` | `corp` / `agent` 抄错,或 `create_auth` 没落库 | 从 `/system/wecom` 复制;查日志 `wecom.auth.apply` |
|
|
146
|
+
| `该企业开通了多个应用,登录链接必须带 agent 参数` | 该企业多个应用,链接没带 `agent` | 补 `agent`(§3) |
|
|
147
|
+
| `已授权多家企业,请在登录链接带 corp 参数以区分` | 链接丢了 `corp`(旧版 cli 的企微内早跳会丢;修复版已透传) | 用 §3 完整链接;若从工作台进仍复现,确认 cli 的 shell-dist 已含修复并重新 `ojm build` |
|
|
148
|
+
| `应用安装失败,联系服务商` | `create_auth` 回调 1 秒窗口超时 | 看服务端日志;重推幂等已处理,已落库的档案不会重复 |
|
|
149
|
+
| `errcode=60020 not allow to access from your ip` | 企业可信 IP 没列全出口 IP | 模板 / 应用后台补齐所有出口 IP |
|
|
150
|
+
| `errcode=60011` / `48002` | 可见范围、四项权限或成员授权模式 | `wecom-daikaifa.md` §2.5 / §2.6 |
|
|
151
|
+
| `登录凭据无效或不在应用可见范围内` | 该员工不在应用可见范围 | 把应用可见范围设为全公司 |
|
|
152
|
+
| `40001` / `42001` gettoken 失败 | 应用 Secret 轮换过 | 重新授权,或重置后重新「验证并接入」 |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 7. 日常运维
|
|
157
|
+
|
|
158
|
+
- **加企业**:重复 §2,零配置变更、零重启。
|
|
159
|
+
- **停企业**:清单里点「停用」→ 级联吊销会话;`cancel_auth` 事件也会停用 + 吊销。
|
|
160
|
+
- **换 Secret / 重置租户管理员口令**:`/system/wecom` 同页操作;重置会置 `must_change=1` 并吊销旧会话。
|
|
161
|
+
- **租户与数据**:租户键就是 `corp_id`,所有运行时路径按它隔离;同一企业多个应用共用一个租户管理员。
|
|
162
|
+
- **相关文档**:`wecom-daikaifa.md`(凭据清单、首次开通顺序、三角色手册)、
|
|
163
|
+
`wecom-internal-app.md`(自建应用与共存、三项备案)。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oj-module/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.67",
|
|
5
5
|
"description": "React Antd 模块工程命令行工具(含预构建宿主 shell-dist)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@faker-js/faker": "^10.4.0",
|
|
52
|
-
"@oj-module/runtime": "0.2.
|
|
52
|
+
"@oj-module/runtime": "0.2.67",
|
|
53
53
|
"@redocly/cli": "^2.51.0",
|
|
54
54
|
"@tailwindcss/vite": "^4.3.0",
|
|
55
55
|
"cac": "^6.7.14",
|
|
@@ -357,6 +357,26 @@ function ensureI18n() {
|
|
|
357
357
|
i18nReady = true;
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* 企微内 P0 早跳的目标 URL。只白名单透传 `corp` / `agent`:多企业专属链接
|
|
362
|
+
* `/login?corp=X&agent=Y` 从工作台打开时,后端 `resolveWecomProfile` 必须拿到
|
|
363
|
+
* 企业代码才能落到正确租户;不带参数会被 `corpSelf()` 吸到本企业,多家档案则
|
|
364
|
+
* 直接 400「已授权多家企业」。票据 / redirect / error 等一律不透传。
|
|
365
|
+
*
|
|
366
|
+
* 与 index.html 内联 BOOT_JS(build.mts)同口径——那道先执行,这里是兜底:
|
|
367
|
+
* 内联脚本被 CSP 拦下或抛异常时,模块加载完仍会走到这里。
|
|
368
|
+
*/
|
|
369
|
+
var EARLY_JUMP_PARAMS = ["corp", "agent"];
|
|
370
|
+
function wecomEarlyJumpUrl() {
|
|
371
|
+
const src = new URLSearchParams(location.search);
|
|
372
|
+
const pass = new URLSearchParams();
|
|
373
|
+
for (const key of EARLY_JUMP_PARAMS) {
|
|
374
|
+
const v = src.get(key)?.trim();
|
|
375
|
+
if (v) pass.set(key, v);
|
|
376
|
+
}
|
|
377
|
+
const qs = pass.toString();
|
|
378
|
+
return `${resolveApiBase()}/auth/wecom/login${qs ? `?${qs}` : ""}`;
|
|
379
|
+
}
|
|
360
380
|
function Boot() {
|
|
361
381
|
const [router, setRouter] = useState(null);
|
|
362
382
|
const [error, setError] = useState(null);
|
|
@@ -365,7 +385,7 @@ function Boot() {
|
|
|
365
385
|
(async () => {
|
|
366
386
|
try {
|
|
367
387
|
if (typeof navigator !== "undefined" && /wxwork/i.test(navigator.userAgent) && location.pathname.endsWith("/login") && !new URLSearchParams(location.search).get("wecom_ticket")) {
|
|
368
|
-
window.location.assign(
|
|
388
|
+
window.location.assign(wecomEarlyJumpUrl());
|
|
369
389
|
return;
|
|
370
390
|
}
|
|
371
391
|
ensureI18n();
|