@microi.net/cli 5.1.8 → 5.2.0

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.
Files changed (39) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/assets/build-meta.json +6 -6
  7. package/cordis.patch.yml +1 -1
  8. package/package.json +1 -1
  9. package/scripts/mcp-server.js +85 -85
  10. package/scripts/microi-cli.js +2 -2
  11. package/scripts/microi-skills.meta.json +216 -201
  12. package/skills/.microi-skills-version.json +2 -2
  13. package/skills/.progressive-disclosure-manifest.json +17 -17
  14. package/skills/README.md +2 -1
  15. package/skills/ai-engine/SKILL.md +7 -2
  16. package/skills/app-store/SKILL.md +81 -81
  17. package/skills/job-engine/SKILL.md +1 -1
  18. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +1 -1
  19. package/skills/microi-docs-coverage/references/capability-map.md +1 -0
  20. package/skills/microi-form-layout/SKILL.md +191 -191
  21. package/skills/microi-frontend-sdk/SKILL.md +189 -182
  22. package/skills/microi-left-right-layout/SKILL.md +2 -0
  23. package/skills/microi-sso/SKILL.md +82 -0
  24. package/skills/microi-sso/references/acceptance.md +49 -0
  25. package/skills/microi-sso/references/configuration-and-security.md +53 -0
  26. package/skills/microi-sso/references/inbound.md +53 -0
  27. package/skills/microi-sso/references/outbound.md +39 -0
  28. package/skills/microi-ui/SKILL.md +11 -7
  29. package/skills/microi.v8.js +5 -2
  30. package/skills/module-engine/SKILL.md +184 -180
  31. package/skills/module-engine/references/module-config.md +4 -2
  32. package/skills/ui-design/SKILL.md +34 -30
  33. package/skills/v8-crud-api/SKILL.md +2 -2
  34. package/skills/v8-debugging/SKILL.md +3 -1
  35. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +3 -2
  36. package/skills/v8-security/SKILL.md +69 -69
  37. package/skills/v8-table-event/SKILL.md +1 -1
  38. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +1 -1
  39. package/skills/v8-utilities/references/server-api-index.md +135 -135
@@ -1,182 +1,189 @@
1
- ---
2
- name: microi-frontend-sdk
3
- description: Microi 前端 SDK 使用规范,适用于 Vue 3、uni-app、H5、PC 网站与 Microi.Client 扩展。用于创建或修改前端请求、登录态、Token 续签、终端会话、上传、文件 URL、ApiEngine、FormEngine 或应用启动代码。
4
- ---
5
-
6
- > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
-
8
- # Microi 前端 SDK
9
-
10
- 所有 Vue 3 前端项目都应使用 `microi.skills/microi.v8.js` 作为统一的 Microi 前端 SDK。新项目不要复制旧版 Vue2/Vuex 请求封装,也不要重新手写 token、上传、文件 URL、ApiEngine 或 FormEngine 层。
11
-
12
- <!-- microi-progressive:begin -->
13
- <!-- microi-progressive:chunk id=microi-frontend-sdk-000 sha256=06f944bc009a4e773ae6d5496d435d3e4a4fdb23d59107dac9cedffcfdf18f86 -->
14
- ## 必须采用的模式
15
-
16
- 将 SDK 复制到项目源码目录,通常是:
17
-
18
- - uni-app: `src/utils/microi.v8.js`
19
- - PC Vue 3 网站: `src/utils/microi.v8.js`
20
- - Microi.Client 扩展页面:如果已有平台请求层就复用;否则从本地工具模块引入 SDK。
21
-
22
- 在项目请求模块里只创建一个已配置实例:
23
-
24
- ```js
25
- import { createMicroiV8 } from './microi.v8.js';
26
-
27
- export const V8 = createMicroiV8({
28
- apiBase: config.apiBase,
29
- fileServer: config.fileServer,
30
- webBase: config.webBase,
31
- osClient: config.osClient,
32
- tokenKey: 'microi_token',
33
- userKey: 'microi_user',
34
- formQueryEngineKey: 'mall_form_query',
35
- maxConcurrent: 8,
36
- appendOsClientQuery: true,
37
- onAuthExpired: () => {
38
- V8.clearToken();
39
- uni.reLaunch({ url: '/pages/login/login' });
40
- }
41
- });
42
- ```
43
-
44
- 在 Vue 3 启动入口挂载:
45
-
46
- ```js
47
- import { V8 } from './utils/request.js';
48
-
49
- export function createApp() {
50
- const app = createSSRApp(App);
51
- V8.install(app);
52
- return { app };
53
- }
54
- ```
55
-
56
- 页面和业务接口模块应从项目请求模块导入已配置实例或薄封装函数,不要直接从标准 skill 文件导入。
57
-
58
- <!-- /microi-progressive:chunk -->
59
- <!-- microi-progressive:chunk id=microi-frontend-sdk-001 sha256=f1c2ab1fadc01dbe8ea4b9de98f7c02192c3f2cfed8b792fe62f8ef516b67d83 -->
60
- ## 必须委托 SDK 的能力
61
-
62
- - `ApiEngine.Run`:直接调用 `/apiengine/{key}` 时使用 `V8.ApiEngine.Run(key, data)`。
63
- - 旧版 `/api/ApiEngine/Run` 只有在老系统仍然需要时才使用 `V8.ApiEngine.RunLegacy(key, data)`。
64
- - FormEngine CRUD 使用 `V8.FormEngine.*`,或使用 `formEngineGet` 这类项目薄封装。
65
- - 上传使用 `V8.uploadFile`。
66
- - 图片、头像、富文本图片、二维码、付款凭证、证件和私有文件使用 `V8.assetUrl`、`V8.resolveFileUrl` 或 `V8.resolveAvatarUrl`。
67
- - Token 与用户缓存使用 `V8.getToken`、`V8.setToken`、`V8.clearToken`、`V8.getUser` 和 `V8.setUser`。
68
- - 公有 HDFS 上的 AI 应用使用 `microi-ai-app-auth.js` 统一桥接登录:页面和只读演示保持匿名可见,首次持久化 `app_*` 操作弹出登录框,登录成功后携带 Token 重试。后端必须再次识别写代码并以 `V8.CurrentUser.Id` 覆盖 `ClientKey`、`ActorKey`、`UserId`,禁止只靠前端按钮判断。
69
- - JavaScript 需要平台安全区数值时使用 `V8.getSafeArea`;CSS 仍使用 `env(safe-area-inset-*)`。
70
-
71
- `Microi.Client` 主后台运行时已内置前后端同构的 `V8.Http.Get/Post/Patch` 及对应 Response 方法;表单事件、按钮 V8 等宿主前端新代码必须优先使用 `V8.Http`,旧 `V8.Post/Get` 仅作兼容保留,其参数和兼容规则以 `v8-http-integration/SKILL.md` 为准。独立项目使用本 SDK、且不在主后台 V8 宿主中时,才使用 SDK 自身的小写 `V8.get/post`、`ApiEngine`、`FormEngine`;不要把它们与宿主旧版大写 `V8.Post/Get` 混为一谈,也不要假设浏览器可以绕过第三方接口的 CORS。
72
-
73
- <!-- /microi-progressive:chunk -->
74
- <!-- microi-progressive:chunk id=microi-frontend-sdk-002 sha256=5842c30af751f60041e4435efe5c993144a874cb2e9d97c41fb37d1f06d6474e -->
75
- ## 登录与验证码封装
76
-
77
- SDK 或项目请求模块必须提供登录所需的系统配置和验证码薄封装,不要让页面散落手写。
78
-
79
- 要求:
80
- - 提供 `isEnabledFlag(value)` 或等价工具,统一判断 `Sys_Config.EnableCaptcha`。它必须把 `true`、`1`、`'true'`、`'1'` 识别为开启,把 `false`、`0`、`'false'`、`'0'`、空值识别为关闭。
81
- - 提供 `getSysConfig()`,内部调用 `V8.GetSysConfig(true)` 或 `/api/DiyTable/GetSysConfig`,并保持当前租户 `OsClient` 一致。
82
- - 提供 `getCaptcha()`,内部调用 `GET /api/Captcha/GetCaptcha`,`responseType:'arraybuffer'`,从响应头读取 `captchaid`,返回 `{ CaptchaId, ImageSrc }`。
83
- - 提供账号登录封装时,只有在页面传入验证码时才追加 `_CaptchaId/_CaptchaValue`;不要在未开启验证码时提交空字段。
84
- - PC Vue、UniApp H5、微信小程序和 App 的账号密码登录都必须使用同一套验证码判断和登录参数契约。
85
-
86
- 参考薄封装:
87
-
88
- ```js
89
- export function isEnabledFlag(value) {
90
- if (value === true || value === 1) return true;
91
- if (typeof value === 'string') {
92
- const text = value.trim().toLowerCase();
93
- return text === '1' || text === 'true' || text === 'yes' || text === 'on';
94
- }
95
- return false;
96
- }
97
-
98
- export async function getSysConfig() {
99
- return await V8.GetSysConfig(true);
100
- }
101
-
102
- export async function login(account, pwd, captcha = {}) {
103
- return V8.Login({
104
- Account: account,
105
- Pwd: pwd,
106
- _CaptchaId: captcha.CaptchaId || undefined,
107
- _CaptchaValue: captcha.CaptchaValue || undefined
108
- });
109
- }
110
- ```
111
-
112
- ### MicroService 独立运行认证(强制)
113
-
114
- AI 生成的前端微服务不能假定永远在主平台 iframe/micro-app 宿主中运行:
115
-
116
- - `window.microApp` 存在且宿主下发 Token 时,直接配置同一个 SDK 实例并进入业务页,不重复显示登录。
117
- - 独立访问时从 `.microi-micro-app.json`/构建配置取得 `apiBase` 与 `osClient`,先复用 SDK 已保存的有效 Token;无 Token 时显示平台帐号密码登录。
118
- - 初始化必须调用 `V8.GetSysConfig(true)` 并按 `EnableCaptcha` 动态决定验证码。验证码接口固定为 `GET /api/Captcha/GetCaptcha`,响应头读取 `captchaid`;只有启用时才向 `V8.Login` 追加 `_CaptchaId/_CaptchaValue`。
119
- - 登录仍签发平台 DiyToken,不创建平行 Token、平行用户表或微服务自有密码体系。失效事件回到登录态,Token 续签仍按本 Skill 的单实例规则处理。
120
- - 宿主额外传入 `permissionContext={sysMenuId,moduleEngineKey,diyTableId}`。SDK/服务层需要访问 FormEngine 时使用真实授权 `moduleEngineKey`;该对象不能代替后端权限,也不能成为放宽匿名接口的理由。
121
-
122
- <!-- /microi-progressive:chunk -->
123
- <!-- microi-progressive:chunk id=microi-frontend-sdk-003 sha256=d5d1984e6cd4efbb2340f984473146c66bb342d60bb571454c457f5673b1c68f -->
124
- ## 请求头规则
125
-
126
- SDK 的 `buildHeaders` 必须集中处理所有请求头,不能让页面、业务 wrapper 或上传逻辑各自拼接租户和鉴权头。
127
-
128
- - `osclient` 必须作为唯一租户请求头键,值来自当前运行期租户,例如 `demo`。写入前删除已有 `OsClient` / `osclient` / 任意大小写变体。
129
- - `Authorization` 写入前也必须删除已有 `Authorization` / `authorization` 变体。需要同时兼容平台 Token 时,可以保留单独的 `Token` 请求头,但它也必须先做大小写去重。
130
- - 页面传入的 `headers` / `header` 要先合并,再统一去重;禁止 `headers.OsClient = ...` 和 `headers.osclient = ...` 同时存在。
131
- - 小程序授权登录、账号登录、刷新 Token、FormEngine、ApiEngine、上传都必须走同一套去重逻辑。
132
- - 验收时检查真实网络请求:不得出现 `osclient: demo, demo`、`Authorization: Bearer xxx, Bearer xxx` 这类逗号合并值。
133
-
134
- <!-- /microi-progressive:chunk -->
135
- <!-- microi-progressive:chunk id=microi-frontend-sdk-004 sha256=c5f546fd4ef770459d42239b40af81d52399a3623340472b703cffe09a7b5d1e -->
136
- ## 上传规则
137
-
138
- `V8.uploadFile` 是 Microi 前端唯一允许的上传入口。SDK 实现必须:
139
-
140
- - 使用 multipart 上传头。`uni.uploadFile` 或 `fetch(FormData)` 不得发送 `Content-Type: application/json`。
141
- - 租户请求头只发送一个键:`osclient`。添加配置租户前,先移除传入的 `osclient` / `OsClient` 重复键。
142
- - `formData` 中发送 `OsClient`;开启 `appendOsClientQuery` 时保留接口查询参数 `?OsClient=tenant`。
143
- - 上传 `Path` 统一从 `options.path`、`formData.Path` 或 `formData.path` 归一化。
144
- - 移动端上传路径必须是安全相对路径,例如 `mall/pay-proof` 或 `mall/member/avatar`。不要使用 `/mall/pay-proof`、完整 URL、磁盘路径、`..`、`:`、`//` 或 `~`。
145
- - 项目薄封装要通过 `{ ...options, path: options.path || defaultPath }` 透传全部选项,避免丢失页面级 `headers`、`action`、`anonymous`、`file`、`formData` 和 `silentError`。
146
- - H5 页面要保留 `uni.chooseImage` 返回的真实 `File` 对象(可用时为 `tempFiles[0].file`)。如果 H5 只返回 `tempFiles[0]` 或 `blob:` / `data:` 临时路径,也要继续传入,不要丢弃。调用 `V8.uploadFile(..., { file, preferFetch:true })`。SDK 必须识别 `File` / `Blob`、`file` / `raw` / `blob` / `originFileObj` 等常见嵌套字段,以及 `blob:` / `data:` 路径,然后优先使用 `fetch + FormData`,必要时在 `uni.uploadFile` 与 fetch 之间回退。
147
- - 上传提交处理不得使用空 `catch`。要用 `body.Msg` / `error.message` 提示用户,记录错误便于诊断,并在 `finally` 中重置上传状态。
148
- - 上传响应与普通请求一样可能通过 `Authorization` / `Token` 响应头轮换登录令牌;`fetch(FormData)` 和 `uni.uploadFile` 成功回调都必须先接收新 Token,再发起后续接口。
149
-
150
- 当上传突然报 `移动端文件上传路径不合法!` 时,先检查实际 multipart 表单字段和请求头。在 Microi 移动端/会员 Token 流程中,后端会在 HDFS 上传前校验 `Path`;错误的 `Content-Type` 会导致后端读不到表单字段,并表现为路径错误。
151
-
152
- <!-- /microi-progressive:chunk -->
153
- <!-- microi-progressive:chunk id=microi-frontend-sdk-005 sha256=1a9d0a33adbff849decf01d114e72cad96f80a6122f0b281cecf9092bbcd0c42 -->
154
- ## 项目封装规则
155
-
156
- 面向业务页面的函数名要保持稳定。如果已有项目导出 `callEngine`、`formEngineGet`、`getImageUrl`、`parseImages` 或 `uploadFile`,保留这些导出,内部委托给 `V8`。这样既能统一 SDK,又能避免大面积改页面。
157
-
158
- 正确写法:
159
-
160
- ```js
161
- export function callEngine(key, params = {}, options = {}) {
162
- return V8.ApiEngine.Run(key, params, { checkCode: true, ...options });
163
- }
164
-
165
- export function getImageUrl(value) {
166
- return V8.assetUrl(value);
167
- }
168
- ```
169
-
170
- 避免写法:
171
-
172
- ```js
173
- uni.request({ url: apiBase + '/apiengine/' + key, header: { Token: token } });
174
- ```
175
-
176
- <!-- /microi-progressive:chunk -->
177
- ## 详细参考路由(渐进披露)
178
-
179
- 仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
180
-
181
- - [references/progressive-01-token-当前登录用户与当前终端登录协议.md](references/progressive-01-token-当前登录用户与当前终端登录协议.md):Token、当前登录用户与当前终端登录协议;仅支持 Vue 3;Key-Value 枚举的跨端约定(强制);界面层独立;验证;搭配 MCI-UI;MicroApp 宿主 Token 同步
182
- <!-- microi-progressive:end -->
1
+ ---
2
+ name: microi-frontend-sdk
3
+ description: Microi 前端 SDK 使用规范,适用于 Vue 3、uni-app、H5、PC 网站与 Microi.Client 扩展。用于创建或修改前端请求、登录态、Token 续签、终端会话、上传、文件 URL、ApiEngine、FormEngine 或应用启动代码。
4
+ ---
5
+
6
+ > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
+
8
+ # Microi 前端 SDK
9
+
10
+ 所有 Vue 3 前端项目都应使用 `microi.skills/microi.v8.js` 作为统一的 Microi 前端 SDK。新项目不要复制旧版 Vue2/Vuex 请求封装,也不要重新手写 token、上传、文件 URL、ApiEngine 或 FormEngine 层。
11
+
12
+ <!-- microi-progressive:begin -->
13
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-000 sha256=06f944bc009a4e773ae6d5496d435d3e4a4fdb23d59107dac9cedffcfdf18f86 -->
14
+ ## 必须采用的模式
15
+
16
+ 将 SDK 复制到项目源码目录,通常是:
17
+
18
+ - uni-app: `src/utils/microi.v8.js`
19
+ - PC Vue 3 网站: `src/utils/microi.v8.js`
20
+ - Microi.Client 扩展页面:如果已有平台请求层就复用;否则从本地工具模块引入 SDK。
21
+
22
+ 在项目请求模块里只创建一个已配置实例:
23
+
24
+ ```js
25
+ import { createMicroiV8 } from './microi.v8.js';
26
+
27
+ export const V8 = createMicroiV8({
28
+ apiBase: config.apiBase,
29
+ fileServer: config.fileServer,
30
+ webBase: config.webBase,
31
+ osClient: config.osClient,
32
+ tokenKey: 'microi_token',
33
+ userKey: 'microi_user',
34
+ formQueryEngineKey: 'mall_form_query',
35
+ maxConcurrent: 8,
36
+ appendOsClientQuery: true,
37
+ onAuthExpired: () => {
38
+ V8.clearToken();
39
+ uni.reLaunch({ url: '/pages/login/login' });
40
+ }
41
+ });
42
+ ```
43
+
44
+ 在 Vue 3 启动入口挂载:
45
+
46
+ ```js
47
+ import { V8 } from './utils/request.js';
48
+
49
+ export function createApp() {
50
+ const app = createSSRApp(App);
51
+ V8.install(app);
52
+ return { app };
53
+ }
54
+ ```
55
+
56
+ 页面和业务接口模块应从项目请求模块导入已配置实例或薄封装函数,不要直接从标准 skill 文件导入。
57
+
58
+ <!-- /microi-progressive:chunk -->
59
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-001 sha256=f1c2ab1fadc01dbe8ea4b9de98f7c02192c3f2cfed8b792fe62f8ef516b67d83 -->
60
+ ## 必须委托 SDK 的能力
61
+
62
+ - `ApiEngine.Run`:直接调用 `/apiengine/{key}` 时使用 `V8.ApiEngine.Run(key, data)`。
63
+ - 旧版 `/api/ApiEngine/Run` 只有在老系统仍然需要时才使用 `V8.ApiEngine.RunLegacy(key, data)`。
64
+ - FormEngine CRUD 使用 `V8.FormEngine.*`,或使用 `formEngineGet` 这类项目薄封装。
65
+ - 上传使用 `V8.uploadFile`。
66
+ - 图片、头像、富文本图片、二维码、付款凭证、证件和私有文件使用 `V8.assetUrl`、`V8.resolveFileUrl` 或 `V8.resolveAvatarUrl`。
67
+ - Token 与用户缓存使用 `V8.getToken`、`V8.setToken`、`V8.clearToken`、`V8.getUser` 和 `V8.setUser`。
68
+ - 公有 HDFS 上的 AI 应用使用 `microi-ai-app-auth.js` 统一桥接登录:页面和只读演示保持匿名可见,首次持久化 `app_*` 操作弹出登录框,登录成功后携带 Token 重试。后端必须再次识别写代码并以 `V8.CurrentUser.Id` 覆盖 `ClientKey`、`ActorKey`、`UserId`,禁止只靠前端按钮判断。
69
+ - JavaScript 需要平台安全区数值时使用 `V8.getSafeArea`;CSS 仍使用 `env(safe-area-inset-*)`。
70
+
71
+ `Microi.Client` 主后台运行时已内置前后端同构的 `V8.Http.Get/Post/Patch` 及对应 Response 方法;表单事件、按钮 V8 等宿主前端新代码必须优先使用 `V8.Http`,旧 `V8.Post/Get` 仅作兼容保留,其参数和兼容规则以 `v8-http-integration/SKILL.md` 为准。独立项目使用本 SDK、且不在主后台 V8 宿主中时,才使用 SDK 自身的小写 `V8.get/post`、`ApiEngine`、`FormEngine`;不要把它们与宿主旧版大写 `V8.Post/Get` 混为一谈,也不要假设浏览器可以绕过第三方接口的 CORS。
72
+
73
+ <!-- /microi-progressive:chunk -->
74
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-002 sha256=5842c30af751f60041e4435efe5c993144a874cb2e9d97c41fb37d1f06d6474e -->
75
+ ## 登录与验证码封装
76
+
77
+ SDK 或项目请求模块必须提供登录所需的系统配置和验证码薄封装,不要让页面散落手写。
78
+
79
+ 要求:
80
+ - 提供 `isEnabledFlag(value)` 或等价工具,统一判断 `Sys_Config.EnableCaptcha`。它必须把 `true`、`1`、`'true'`、`'1'` 识别为开启,把 `false`、`0`、`'false'`、`'0'`、空值识别为关闭。
81
+ - 提供 `getSysConfig()`,内部调用 `V8.GetSysConfig(true)` 或 `/api/DiyTable/GetSysConfig`,并保持当前租户 `OsClient` 一致。
82
+ - 提供 `getCaptcha()`,内部调用 `GET /api/Captcha/GetCaptcha`,`responseType:'arraybuffer'`,从响应头读取 `captchaid`,返回 `{ CaptchaId, ImageSrc }`。
83
+ - 提供账号登录封装时,只有在页面传入验证码时才追加 `_CaptchaId/_CaptchaValue`;不要在未开启验证码时提交空字段。
84
+ - PC Vue、UniApp H5、微信小程序和 App 的账号密码登录都必须使用同一套验证码判断和登录参数契约。
85
+
86
+ 参考薄封装:
87
+
88
+ ```js
89
+ export function isEnabledFlag(value) {
90
+ if (value === true || value === 1) return true;
91
+ if (typeof value === 'string') {
92
+ const text = value.trim().toLowerCase();
93
+ return text === '1' || text === 'true' || text === 'yes' || text === 'on';
94
+ }
95
+ return false;
96
+ }
97
+
98
+ export async function getSysConfig() {
99
+ return await V8.GetSysConfig(true);
100
+ }
101
+
102
+ export async function login(account, pwd, captcha = {}) {
103
+ return V8.Login({
104
+ Account: account,
105
+ Pwd: pwd,
106
+ _CaptchaId: captcha.CaptchaId || undefined,
107
+ _CaptchaValue: captcha.CaptchaValue || undefined
108
+ });
109
+ }
110
+ ```
111
+
112
+ ### MicroService 独立运行认证(强制)
113
+
114
+ AI 生成的前端微服务不能假定永远在主平台 iframe/micro-app 宿主中运行:
115
+
116
+ - `window.microApp` 存在且宿主下发 Token 时,直接配置同一个 SDK 实例并进入业务页,不重复显示登录。
117
+ - 独立访问时从 `.microi-micro-app.json`/构建配置取得 `apiBase` 与 `osClient`,先复用 SDK 已保存的有效 Token;无 Token 时显示平台帐号密码登录。
118
+ - 初始化必须调用 `V8.GetSysConfig(true)` 并按 `EnableCaptcha` 动态决定验证码。验证码接口固定为 `GET /api/Captcha/GetCaptcha`,响应头读取 `captchaid`;只有启用时才向 `V8.Login` 追加 `_CaptchaId/_CaptchaValue`。
119
+ - 登录仍签发平台 DiyToken,不创建平行 Token、平行用户表或微服务自有密码体系。失效事件回到登录态,Token 续签仍按本 Skill 的单实例规则处理。
120
+ - 宿主额外传入 `permissionContext={sysMenuId,moduleEngineKey,diyTableId}`。SDK/服务层需要访问 FormEngine 时使用真实授权 `moduleEngineKey`;该对象不能代替后端权限,也不能成为放宽匿名接口的理由。
121
+
122
+ <!-- /microi-progressive:chunk -->
123
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-003 sha256=d5d1984e6cd4efbb2340f984473146c66bb342d60bb571454c457f5673b1c68f -->
124
+ ## 请求头规则
125
+
126
+ SDK 的 `buildHeaders` 必须集中处理所有请求头,不能让页面、业务 wrapper 或上传逻辑各自拼接租户和鉴权头。
127
+
128
+ - `osclient` 必须作为唯一租户请求头键,值来自当前运行期租户,例如 `demo`。写入前删除已有 `OsClient` / `osclient` / 任意大小写变体。
129
+ - `Authorization` 写入前也必须删除已有 `Authorization` / `authorization` 变体。需要同时兼容平台 Token 时,可以保留单独的 `Token` 请求头,但它也必须先做大小写去重。
130
+ - 页面传入的 `headers` / `header` 要先合并,再统一去重;禁止 `headers.OsClient = ...` 和 `headers.osclient = ...` 同时存在。
131
+ - 小程序授权登录、账号登录、刷新 Token、FormEngine、ApiEngine、上传都必须走同一套去重逻辑。
132
+ - 验收时检查真实网络请求:不得出现 `osclient: demo, demo`、`Authorization: Bearer xxx, Bearer xxx` 这类逗号合并值。
133
+
134
+ <!-- /microi-progressive:chunk -->
135
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-004 sha256=c5f546fd4ef770459d42239b40af81d52399a3623340472b703cffe09a7b5d1e -->
136
+ ## 上传规则
137
+
138
+ `V8.uploadFile` 是 Microi 前端唯一允许的上传入口。SDK 实现必须:
139
+
140
+ - 使用 multipart 上传头。`uni.uploadFile` 或 `fetch(FormData)` 不得发送 `Content-Type: application/json`。
141
+ - 租户请求头只发送一个键:`osclient`。添加配置租户前,先移除传入的 `osclient` / `OsClient` 重复键。
142
+ - `formData` 中发送 `OsClient`;开启 `appendOsClientQuery` 时保留接口查询参数 `?OsClient=tenant`。
143
+ - 上传 `Path` 统一从 `options.path`、`formData.Path` 或 `formData.path` 归一化。
144
+ - 移动端上传路径必须是安全相对路径,例如 `mall/pay-proof` 或 `mall/member/avatar`。不要使用 `/mall/pay-proof`、完整 URL、磁盘路径、`..`、`:`、`//` 或 `~`。
145
+ - 项目薄封装要通过 `{ ...options, path: options.path || defaultPath }` 透传全部选项,避免丢失页面级 `headers`、`action`、`anonymous`、`file`、`formData` 和 `silentError`。
146
+ - H5 页面要保留 `uni.chooseImage` 返回的真实 `File` 对象(可用时为 `tempFiles[0].file`)。如果 H5 只返回 `tempFiles[0]` 或 `blob:` / `data:` 临时路径,也要继续传入,不要丢弃。调用 `V8.uploadFile(..., { file, preferFetch:true })`。SDK 必须识别 `File` / `Blob`、`file` / `raw` / `blob` / `originFileObj` 等常见嵌套字段,以及 `blob:` / `data:` 路径,然后优先使用 `fetch + FormData`,必要时在 `uni.uploadFile` 与 fetch 之间回退。
147
+ - 上传提交处理不得使用空 `catch`。要用 `body.Msg` / `error.message` 提示用户,记录错误便于诊断,并在 `finally` 中重置上传状态。
148
+ - 上传响应与普通请求一样可能通过 `Authorization` / `Token` 响应头轮换登录令牌;`fetch(FormData)` 和 `uni.uploadFile` 成功回调都必须先接收新 Token,再发起后续接口。
149
+
150
+ 当上传突然报 `移动端文件上传路径不合法!` 时,先检查实际 multipart 表单字段和请求头。在 Microi 移动端/会员 Token 流程中,后端会在 HDFS 上传前校验 `Path`;错误的 `Content-Type` 会导致后端读不到表单字段,并表现为路径错误。
151
+
152
+ <!-- /microi-progressive:chunk -->
153
+ <!-- microi-progressive:chunk id=microi-frontend-sdk-005 sha256=1a9d0a33adbff849decf01d114e72cad96f80a6122f0b281cecf9092bbcd0c42 -->
154
+ ## 项目封装规则
155
+
156
+ 面向业务页面的函数名要保持稳定。如果已有项目导出 `callEngine`、`formEngineGet`、`getImageUrl`、`parseImages` 或 `uploadFile`,保留这些导出,内部委托给 `V8`。这样既能统一 SDK,又能避免大面积改页面。
157
+
158
+ 正确写法:
159
+
160
+ ```js
161
+ export function callEngine(key, params = {}, options = {}) {
162
+ return V8.ApiEngine.Run(key, params, { checkCode: true, ...options });
163
+ }
164
+
165
+ export function getImageUrl(value) {
166
+ return V8.assetUrl(value);
167
+ }
168
+ ```
169
+
170
+ 避免写法:
171
+
172
+ ```js
173
+ uni.request({ url: apiBase + '/apiengine/' + key, header: { Token: token } });
174
+ ```
175
+
176
+ <!-- /microi-progressive:chunk -->
177
+ ## 详细参考路由(渐进披露)
178
+
179
+ 仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
180
+
181
+ - [references/progressive-01-token-当前登录用户与当前终端登录协议.md](references/progressive-01-token-当前登录用户与当前终端登录协议.md):Token、当前登录用户与当前终端登录协议;仅支持 Vue 3;Key-Value 枚举的跨端约定(强制);界面层独立;验证;搭配 MCI-UI;MicroApp 宿主 Token 同步
182
+ <!-- microi-progressive:end -->
183
+
184
+ ## 复盘:FormEngine 新增请求只在外层保留 Id
185
+
186
+ - 触发场景:uni-app/微信小程序预生成记录 Id 后调用 `V8.FormEngine.AddFormData(table, row)`,服务端表单事件中 `V8.Form.Id` 仍为空,按父 Id 查询子表时误命中外键为空的孤儿数据。
187
+ - 根因:SDK 将 `Id` 从业务行模型 `_RowModel` 中移出后只写到请求外层;外层 Id 可用于接口寻址,但不会稳定进入表单事件的 `V8.Form`。
188
+ - 通用规则:新增请求遇到 `Id` 时必须同时保留 `request.Id` 与 `request._RowModel.Id`;服务端涉及父子表聚合或删除的事件还必须对父 Id 做非空熔断,禁止使用空值或 `Like` 查询子表。
189
+ - 自动化检查:FormEngine 写入契约测试必须断言预生成 Id 在请求外层和 `_RowModel` 中完全一致,并覆盖后端事件在空 Id 时拒绝执行、有效 Id 时只查询对应子记录。
@@ -54,6 +54,7 @@ description: Microi 吾码模块引擎“树形+表格/表单”左右结构配
54
54
  | `YincangBSF` | 否 | 节点命中该字段时隐藏右侧区域。 |
55
55
  | `TanchuangLX`、`TanchuangDX` | 否 | 树节点维护弹窗类型和尺寸。 |
56
56
  | `LanjiaZ`、`LanjiaZDM` | 否 | 懒加载开关和代码;大树优先使用。 |
57
+ | `DefaultExpandLevel` | 否 | 左树默认展开层级。未配置、空值或 `0` 均不展开;`1` 展开一级节点,`2` 再展开二级节点,以此类推。 |
57
58
 
58
59
  ## 初始化 V8 与分页契约
59
60
 
@@ -132,6 +133,7 @@ V8.Result = {
132
133
  - 左树标题无 `undefined`、`{}`、空白重复项。
133
134
  - 点击“全部”清空右侧外键条件;点击节点只显示该节点数据。
134
135
  - 后端 `_HasChild=true` 表示可展开,Element Plus 的 `isLeaf` 必须映射为独立 `_IsLeaf=!_HasChild`,不得把 `_HasChild` 直接当叶子标记。
136
+ - `DefaultExpandLevel` 未配置时必须保持全部折叠;只展开有子节点且深度不超过配置值的节点,不能把平台默认值改成一级展开。
135
137
  - 页面初始已处于“全部”时,再次点击“全部”不得先清空已加载列表;只清除树节点外键条件并避免重复请求。
136
138
  - 右侧新增数据自动写入正确外键,切换节点后不会串数据。
137
139
  - 普通用户不出现仅管理员可用的“页面配置”。
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: microi-sso
3
+ description: 设计、实现、配置、迁移、发布和验收 Microi 吾码双向 SSO 身份联邦。用于外部系统通过 OIDC、SAML2、CAS 登录吾码,或吾码作为 OIDC OP、SAML IdP、CAS Server 集成其它系统,以及 diy_sso、账号/角色映射、Secret/证书、官方应用 app.microi.sso 和真实伙伴联调。
4
+ ---
5
+
6
+ > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
+
8
+ # Microi SSO 身份联邦
9
+
10
+ ## 何时使用
11
+
12
+ 以下任务必须使用本 Skill:
13
+
14
+ - Keycloak、Entra ID、ADFS、CAS Server、企业统一身份中心登录吾码。
15
+ - 吾码账号登录 ERP、OA、BI、门户或其它第三方系统。
16
+ - 修改 `diy_sso`、SSO 登录页、OIDC/SAML/CAS Controller、Claim/角色映射或旧 Token SSO。
17
+ - 发布、安装、升级或验收官方商城应用 `app.microi.sso`。
18
+
19
+ 固定 Gitee、微信、GitHub 登录与 Passkey/TOTP 仍以 `v8-security` 为主;当需求是可配置企业身份联邦时转到本 Skill。
20
+
21
+ ## 先读取什么
22
+
23
+ 按任务读取,不要一次加载全部参考:
24
+
25
+ - 外部身份源登录吾码:读 [references/inbound.md](references/inbound.md)。
26
+ - 吾码给第三方提供登录:读 [references/outbound.md](references/outbound.md)。
27
+ - 表字段、Secret、证书、安全与存量迁移:读 [references/configuration-and-security.md](references/configuration-and-security.md)。
28
+ - 测试、商城发布、目标安装与交付结论:读 [references/acceptance.md](references/acceptance.md)。
29
+
30
+ 源码修改前同时完整读取 `workspace-conventions/SKILL.md`;认证、DiyToken、秘密或权限任务再读 `v8-security/SKILL.md`;商城任务再读 `app-store/SKILL.md`。
31
+
32
+ ## 不可破坏的事实
33
+
34
+ 1. DiyToken 是进入吾码后的唯一平台会话入口。SSO 认证成功后签发 DiyToken,不创建第二套用户/权限 Token。
35
+ 2. 吾码向外提供的 OIDC/SAML/CAS 协议票据独立、短期、可撤销,绝不把 DiyToken 给第三方。
36
+ 3. `OsClient + ConnectionKey + Subject` 是外部主体隔离边界;所有回调、票据、缓存和审计都绑定租户。
37
+ 4. 新连接只用 OIDC、SAML2、CAS;URL Token 是迁移兼容项,不是推荐协议。
38
+ 5. Redirect URI、ACS、Destination、Audience 和 CAS service 必须精确匹配;生产端点必须 HTTPS。
39
+ 6. Secret/私钥只存 `mci_system_setting` 的受控值;`diy_sso` 只存 Setting Key。匿名接口只返回登录入口白名单投影。
40
+ 7. 外部角色、邮箱或昵称不能直接获得管理员权限。默认 `BoundOnly`,JIT 必须显式默认角色、唯一性、回收和审计。
41
+ 8. HTTP 200、构建成功、商城任务入队或包可下载都不是完整 SSO 验收。
42
+ 9. SSO 业务逻辑必须接口引擎优先:连接投影、绑定/JIT、角色与 Claim 映射、审计、登录完成和租户扩展不得重新写进 Controller。只有协议报文、签名验签、Secret/私钥隔离、一次性票据与 DiyToken 等可信原子可以保留 C#。
43
+ 10. 客户端调用应用接口使用稳定 `/api/ApiEngine/Run?OsClient=`;应用未安装时必须得到结构化错误,禁止重新依赖可能由网关缺失而 404 的动态 `/apiengine/*` 或已删除的 `/api/Sso/Capabilities` 等定制路由。
44
+
45
+ ## 标准工作流
46
+
47
+ 1. 识别方向、协议、租户、身份伙伴、用户生命周期、退出和密钥/证书责任人。
48
+ 2. 读取当前 `diy_sso` Schema、菜单、真实连接和已部署 Server/Client 版本;不要从旧截图猜测。
49
+ 3. 先选标准协议和安全 profile,再配置字段、Secret/证书 Key、Claim/角色映射。
50
+ 4. 先把业务编排写成可随应用发布的接口引擎;仅当现有 V8 无法安全完成底层原子能力时,才扩展最小 `V8.Method`,并把调用权限制到精确官方接口 Key。禁止把整个流程放进新 Controller,也禁止让原子方法接受任意租户、回调地址或 Secret。
51
+ 5. 分别验证源码/单测、后端构建、前端构建、运行时端点、浏览器 UI、真实伙伴和多节点。
52
+ 6. 平台级资源通过官方应用包发布;官方源用 `microi_itdos` 更新并发布,普通目标租户走商城安装/升级任务。
53
+ 7. 最终明确已验证与未验证边界,尤其是“配置包已发布”与“运行时代码已部署”的区别。
54
+
55
+ ## 官方应用合同
56
+
57
+ - AppId:`app.microi.sso`
58
+ - 名称:`SSO 身份联邦`
59
+ - 资源:`diy_sso`、`/system/sso`、字段/布局/视图、10 个 Managed 核心接口引擎和 1 个 CreateIfMissing 租户 Hook;不发布用户绑定、连接实例、Secret、证书或示例账号。
60
+ - `ResourcePolicies.ApiEngines` 必须逐 Key 显式声明。核心使用 `Managed/Application`;`sso_event_hook` 使用 `CreateIfMissing/Tenant`,安装后永不被官方覆盖。
61
+ - 官方 `iTdos` 是发布源,保护性拒绝安装属于正确行为;普通租户安装才必须轮询到 `Succeeded`。
62
+
63
+ ## C# 与接口引擎责任线
64
+
65
+ 接口引擎固定承载:
66
+
67
+ - `sso_capabilities`、`sso_legacy_capabilities` 的匿名白名单投影;
68
+ - `sso_connection_runtime`、`sso_user_runtime` 的内部最小投影;
69
+ - `sso_resolve_federated_identity` 的绑定、JIT 与角色映射;
70
+ - `sso_outbound_claims`、`sso_protocol_event`、`sso_event_hook`;
71
+ - `sso_complete_login`、`sso_rotate_client_secret`、`sso_legacy_token_login` 的业务编排。
72
+
73
+ C# 只保留:
74
+
75
+ - OIDC/SAML/CAS 原始 HTTP/重定向/XML/JWT 报文与签名验签;
76
+ - Secret、私钥、证书和协议 Token 的可信隔离;
77
+ - 高熵一次性 code/ticket、重放保护和 DiyToken 签发;
78
+ - 仅允许精确 Managed Key 调用的 `CreateFederatedUser`、`CreateSsoLoginTicket`、`CompleteSsoLogin`、`RotateSsoClientSecret` 原子。
79
+
80
+ 新增 SSO 需求先判断是否只需修改上述接口引擎。只有缺少不可伪造、不可泄露的底层原子时才增加 V8 方法;增加后同时更新应用 `RequiredPlatformCapabilities`、后端文档、测试与最低版本。
81
+
82
+ 详细用户文档:`microi.doc/docs/doc/more/sso.md`。
@@ -0,0 +1,49 @@
1
+ # 验收、商城发布与交付结论
2
+
3
+ ## 分层证据
4
+
5
+ | 层 | 最低证据 |
6
+ |---|---|
7
+ | 源码 | 协议/安全原语测试,静态扫描无 Secret/Token 日志 |
8
+ | 后端构建 | 隔离输出 `dotnet build` 成功,不覆盖共享运行目录 |
9
+ | 前端构建 | 现代包和项目要求的兼容包完成 |
10
+ | 应用包 | 可重复生成;Name/AppId/Version、DDL、字段数、菜单、空数据集、11 个接口引擎源码同源与 ResourcePolicies 校验 |
11
+ | 官方商城 | `microi_itdos` 发布后回读 `sys_microistore` 与官方资源 API;状态、版本、包哈希一致 |
12
+ | 目标租户 | 安装/升级任务终态 `Succeeded`,再读真实表、字段、菜单、安装版本 |
13
+ | 运行时 | Capabilities、Discovery/Metadata/JWKS 和实际使用端点命中已部署程序集 |
14
+ | 浏览器 | 登录入口、弹窗 Origin、URL 清理、管理页 7 Tab、秘密无明文 |
15
+ | 伙伴联调 | 登录/拒绝/过期/重放/退出/停用/角色变化/轮换 |
16
+ | 多节点 | state、code、ticket、session、撤销和缓存跨节点一致 |
17
+
18
+ ## 官方应用发布
19
+
20
+ 1. 使用官方 `microi_itdos`,核对绑定 `https://api.itdos.com` 与 `OsClient=iTdos`。
21
+ 2. 在发布源更新真实 `diy_sso`、字段、表单 Tabs 和菜单视图并回读。
22
+ 3. 导出精确菜单/表和 11 个接口引擎,不带连接数据、用户绑定、Secret、证书或示例账号;接口源码必须与 `Microi-V8-Engine/.../SSO身份联邦` 逐字同源。
23
+ 4. AppId 固定 `app.microi.sso`,PublisherType 为官方应用;10 个核心 Key 为 `Managed/Application`,`sso_event_hook` 为 `CreateIfMissing/Tenant`。
24
+ 5. 发布后从官方资源 API 读取 `app.microi.sso.json`,校验 SHA-256、版本、1 菜单、1 表、64 字段、11 个接口引擎及策略。
25
+ 6. 官方 iTdos 是发布源,安装任务被“发布源不允许安装”拒绝是保护性终态;不要绕过或伪装成成功。
26
+ 7. 普通目标租户才执行安装/更新,并轮询后台任务到终态。Pending/Running/入队不算成功。
27
+
28
+ ## 协议负向用例
29
+
30
+ - OIDC:state/nonce/PKCE 错、code 重放、issuer/audience 错、未知 kid、过期 token、refresh 重放、回调前缀攻击。
31
+ - SAML:签名错、过期、Audience/Destination/InResponseTo 错、Request/Assertion 重放、错误证书、未授权 ACS。
32
+ - CAS:ticket 重放、service 不同、过期 ticket、错误租户、CAS 失败响应。
33
+ - 通用:跨租户连接、停用用户、停用连接、SSRF 私网/回环、访问密钥会话授权、匿名读取 `diy_sso`。
34
+
35
+ ## 结论措辞
36
+
37
+ 只有真实伙伴和多节点验收也通过,才能说“该协议连接已可生产使用”。
38
+
39
+ - 包已发布但 Server/Client 未部署:写“官方配置包已发布,运行时代码待部署”。
40
+ - 端点冒烟通过但无真实 IdP/SP:写“协议端点已验证,伙伴联调待完成”。
41
+ - 官方源安装被保护性拒绝:写“发布源保护生效,不构成普通租户安装证据”。
42
+ - 因用户未授权输入密码而无法浏览器登录:写明 UI 登录后验收未完成,不用接口/源码代替视觉证据。
43
+
44
+ ## 404 与应用缺失回归
45
+
46
+ - 客户端能力发现和登录完成只允许调用 `/api/ApiEngine/Run?OsClient=`,请求体携带精确 `ApiEngineKey`。
47
+ - 在未安装 `app.microi.sso` 的租户调用通用入口,应返回结构化“接口引擎不存在”;不能返回 `/api/Sso/Capabilities` 路由 404。
48
+ - 安装后回读 11 个 `sys_apiengine` 行并刷新缓存,再验证 `sso_capabilities` 为 `Code=1`。
49
+ - `/api/Sso/Capabilities`、`LegacyCapabilities`、`CompleteLogin`、`RotateClientSecret` 与 `/api/SysUser/SsoPengrui` 必须保持删除,防止业务逻辑重新漂回 Controller。
@@ -0,0 +1,53 @@
1
+ # 配置、Secret、安全与迁移
2
+
3
+ ## diy_sso 分组
4
+
5
+ - `basic`:Key、名称、方向、协议、启用、排序。
6
+ - `oidc`:Issuer/Discovery/端点、Client、Scope、精确 Redirect URI。
7
+ - `saml`:Entity ID、Metadata、SSO/SLO、ACS。
8
+ - `cas`:Server URL、版本。
9
+ - `mapping`:Subject/Account/Name/Email/Role Claim、JSON 映射、JIT。
10
+ - `security`:Secret/证书设置 Key、签名/加密、PKCE/nonce、生命周期、私网开关。
11
+ - `legacy`:旧 Server/Client API、TokenName、GetTokenType。
12
+
13
+ `diy_sso` 是管理员专用平台表。匿名能力接口只投影 ConnectionKey、名称、协议、图标、说明和发起地址;旧兼容投影只允许同源 `/api/` 路径与安全 Token 参数名。
14
+
15
+ 匿名投影由 `sso_capabilities` / `sso_legacy_capabilities` 接口引擎提供;Controller 不得直接查询并返回 `diy_sso`。内部协议网关通过 StopHttp 的 `sso_connection_runtime` 取得最小运行投影。客户端统一调用 `/api/ApiEngine/Run?OsClient=`,避免应用尚未安装或网关未注册动态路由时出现 404。
16
+
17
+ ## Secret 与证书
18
+
19
+ - `ClientSecretSettingKey` 等字段只存 `mci_system_setting` Key。
20
+ - 第三方 Client Secret 和私钥证书使用后端 Secret 存储,不出现在日志、导出、包、浏览器或 MCP 回读。
21
+ - 吾码对外 OIDC Client Secret 只存专用密码哈希;不能用 AES/DES 代替验证哈希。
22
+ - SAML 验签/加密公开证书与签名/解密私钥严格区分用途。
23
+ - 证书/签名 Key 轮换要有新旧重叠、伙伴确认、撤销和回滚窗口。
24
+
25
+ ## 网络和 URL
26
+
27
+ 所有外部 Discovery、JWKS、Metadata、Token、UserInfo 地址先过 HTTPS/SSRF 检查。默认拒绝回环、私网、链路本地、带用户信息 URL 和 DNS 重绑定;内网 IdP 只能由管理员显式开启并用网络出口白名单补强。
28
+
29
+ Redirect/Logout/ACS/CAS service 使用规范化后的绝对 URL 精确比较。不要允许通配符、子域后缀、前缀或 fragment。反向代理下使用可信外部 Origin,不能根据任意 Host/Header 构造安全回调。
30
+
31
+ ## 账号与角色
32
+
33
+ 默认 `BoundOnly`。JIT 需要:
34
+
35
+ - 稳定 Subject 与账号唯一性。
36
+ - 非管理员默认角色。
37
+ - 外部角色到 RoleId 的显式 allowlist。
38
+ - 离职、禁用、角色收回与冲突处理。
39
+ - 创建、匹配、拒绝和变更审计。
40
+
41
+ 这些规则由 Managed `sso_resolve_federated_identity` 编排。JIT 创建最终调用精确受限的 `V8.Method.CreateFederatedUser` 原子,并用平台专用带盐密码哈希写入不可登录的随机初始密码;不得回退到 DES,也不得把外部角色名直接写成平台 RoleId。
42
+
43
+ 不能把外部 `admin` 字符串、邮箱域或昵称直接解释为平台管理员。
44
+
45
+ ## LegacyToken 迁移
46
+
47
+ 1. 盘点旧 `ClientSsoApi/ServerSsoApi/TokenName` 和使用系统。
48
+ 2. 为每个系统选择 OIDC、SAML2 或 CAS 并建立新连接。
49
+ 3. 并行验证登录/退出和账号映射;新入口默认标准协议。
50
+ 4. URL 中的旧 Token 读取后立即清理,不写 Referer、日志或分析平台。
51
+ 5. 迁移完成后停用旧行;不要继续给新系统复制 LegacyToken。
52
+
53
+ 旧兼容只允许调用同源 `/api/`,绝不把 DiyToken POST 到管理员配置的任意绝对 URL。浏览器只处理 `LegacyCapabilities` 已返回连接中明确登记的 `TokenName`;不得恢复“只要 URL 出现 `?token=` 就自动登录”的无配置旁路。