@acosmi/sdk-ts 2.0.0 → 2.1.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.
- package/CHANGELOG.md +23 -0
- package/README.md +240 -54
- package/dist/browser/index.mjs +403 -3
- package/dist/browser/index.mjs.map +1 -1
- package/dist/index.mjs +403 -3
- package/dist/index.mjs.map +1 -1
- package/dist/node/index.cjs +421 -2
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +447 -3
- package/dist/node/index.d.ts +447 -3
- package/dist/node/index.mjs +403 -3
- package/dist/node/index.mjs.map +1 -1
- package/docs/pii-role-matrix.md +178 -0
- package/docs//345/274/200/345/217/221/344/270/216/345/217/221/345/270/203/346/211/213/345/206/214.md +831 -0
- package/package.json +3 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# PII 角色可见性矩阵 (v1.9.0+)
|
|
2
|
+
|
|
3
|
+
> 适用版本: `@acosmi/sdk-ts` v1.9.0+
|
|
4
|
+
> 对应主仓: K10a PII Aspect (`@FieldEncrypt` / `@Sensitive` 切面) + IMPL-A 角色严格化
|
|
5
|
+
> 最后更新: 2026-05-25
|
|
6
|
+
|
|
7
|
+
## 1. 背景
|
|
8
|
+
|
|
9
|
+
商品化 P1-P7 Phase 3 收口时, 主仓 (tk-dist Java) 完成两条根因修复并随 SDK v1.9.0
|
|
10
|
+
发布:
|
|
11
|
+
|
|
12
|
+
- **K10a PII Aspect**: `dist_invoice` / `dist_corporate_transfer` / `dist_refund_record`
|
|
13
|
+
等 finance 表族 + `dist_lawyer_profile` 法律表族 + `dist_enterprise_*` 企业席位表族
|
|
14
|
+
敏感列改走 `@FieldEncrypt` 切面真加密落盘. V63 列宽 VARCHAR→TEXT 兜密文; V64 backfill
|
|
15
|
+
老明文 → v2 payload.
|
|
16
|
+
|
|
17
|
+
- **IMPL-A 角色严格化** (`SensitiveSerializer.normalizeAuthority`): yudao 通用
|
|
18
|
+
`ROLE_ADMIN` / `ROLE_USER` / `INTERNAL` 三个老别名 fail-OPEN 升级为 platform_admin
|
|
19
|
+
视角的隐患已根治. 调用方传 token 必须真有正式角色, 否则视同 guest.
|
|
20
|
+
|
|
21
|
+
SDK 边界: 类型注释只描述 PII 级别, 不内置脱敏逻辑 — 真实脱敏由后端 `PiiDesensitizer`
|
|
22
|
+
按角色返回不同字符串 (明文 / `***1234` / 全 `***`). SDK 调用方 (Web / Desktop / CLI)
|
|
23
|
+
需理解角色矩阵以正确渲染.
|
|
24
|
+
|
|
25
|
+
## 2. 4 角色枚举
|
|
26
|
+
|
|
27
|
+
来源: `SensitiveSerializer.normalizeAuthority` (主仓
|
|
28
|
+
`yudao-module-distribution/...impl/serializer/SensitiveSerializer.java`).
|
|
29
|
+
|
|
30
|
+
| 角色常量 | 含义 | 典型颁发方 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `ROLE_PLATFORM_ADMIN` | 平台管理员 (跨租户) — 后台运营 / 客服 / 财务工作台 | 主仓 yudao admin 登录 + claim platform_admin |
|
|
33
|
+
| `ROLE_S2S` | 服务对服务调用 — Nexus Go 网关 / 微服务内部互调 | S2S Token (X-Service-Secret) |
|
|
34
|
+
| `ROLE_LAWYER` | 律师 — 仅查看自己执业资料 + 自己接单的案件 | C 端登录 + 律师资质审核通过 |
|
|
35
|
+
| `ROLE_CONSUMER` | 消费者 — 普通 C 端用户, 仅查看自己的数据 | C 端 OAuth (`/api/consumer/**`) |
|
|
36
|
+
| (guest / unknown) | 匿名 / 未登录 / 角色不匹配 | 无 token / Bearer 无效 / 角色字符串非上述 4 个 |
|
|
37
|
+
|
|
38
|
+
## 3. PII 级 × 角色矩阵
|
|
39
|
+
|
|
40
|
+
PII 分 3 级 (与 `@Sensitive(level=...)` 严格对齐):
|
|
41
|
+
|
|
42
|
+
- **L1 公开** — 任何场景明文 (id / orderId / amountFen / status / createdAt 等)
|
|
43
|
+
- **L2 半遮** — 部分场景半遮 (title / contactAddress / nickname / avatarUrl 等)
|
|
44
|
+
- **L3 仅 admin** — 强敏感字段, 默认全脱敏 (taxId / bankAccount / contactPhone /
|
|
45
|
+
bankName / licenseNo / idCardNo 等)
|
|
46
|
+
|
|
47
|
+
| 角色 | L1 公开 | L2 半遮 | L3 仅 admin |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `ROLE_PLATFORM_ADMIN` | 明文 | 明文 | 明文 |
|
|
50
|
+
| `ROLE_S2S` | 明文 | 明文 | 明文 |
|
|
51
|
+
| `ROLE_LAWYER` | 明文 | 明文 | 脱敏 (`***1234`) |
|
|
52
|
+
| `ROLE_CONSUMER` | 明文 | 明文 | 脱敏 (`***1234`) |
|
|
53
|
+
| (guest / unknown) | 明文 | 脱敏 | 脱敏 |
|
|
54
|
+
|
|
55
|
+
> **Note**: `ROLE_LAWYER` / `ROLE_CONSUMER` 自己的数据 L3 字段仍可通过专门的 admin 直读
|
|
56
|
+
> 端点 (`/api/distribution/**/me/decrypted`) 解密, 但默认 listMyXxx 端点走脱敏视图.
|
|
57
|
+
> SDK 类型上不强制 — 调用方按上下文判定.
|
|
58
|
+
|
|
59
|
+
## 4. Breaking Change — v1.9.0+ 旧别名失效
|
|
60
|
+
|
|
61
|
+
主仓 IMPL-A 角色严格化把以下 3 条 fail-OPEN 别名根治:
|
|
62
|
+
|
|
63
|
+
| 旧别名 (≤ v1.8.x) | 误升级到 (旧行为) | v1.9.0+ 处理 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `ROLE_ADMIN` | `platform_admin` (L3 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
66
|
+
| `ROLE_USER` | `consumer` (L1/L2 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
67
|
+
| `INTERNAL` | `s2s` (L3 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
68
|
+
|
|
69
|
+
### 集成方应对
|
|
70
|
+
|
|
71
|
+
1. **token 升级到正式角色**: yudao admin 后台 token 改派发 `ROLE_PLATFORM_ADMIN`;
|
|
72
|
+
微服务 S2S 调用切到 `ROLE_S2S` claim; C 端 OAuth 已自动派发 `ROLE_CONSUMER`.
|
|
73
|
+
2. **fallback 走 guest 视角**: 升级期 (灰度) 旧 token 调用 `/api/distribution/admin/**`
|
|
74
|
+
会拿到脱敏数据 — 这是设计内行为, 不是 bug.
|
|
75
|
+
3. **角色字符串大小写敏感**: 必须全大写 `ROLE_PLATFORM_ADMIN`, 小写 / 缺前缀的
|
|
76
|
+
`platform_admin` 会被 `normalizeAuthority` 拒绝.
|
|
77
|
+
|
|
78
|
+
## 5. 实际生效字段示例
|
|
79
|
+
|
|
80
|
+
按 v1.9.0 SDK 主要类型清单 (与主仓 `@Sensitive` 注解严格对齐):
|
|
81
|
+
|
|
82
|
+
### finance namespace (`src/finance/types.ts`)
|
|
83
|
+
|
|
84
|
+
| 字段 | 级别 | 角色匹配后明文示例 | guest 视图 |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `Invoice.id / invoiceNo / orderId / amountFen / status` | L1 | `INV20260525001` | 同 |
|
|
87
|
+
| `Invoice.title` | L2 | `Acosmi Tech Ltd` | `Acos*****td` |
|
|
88
|
+
| `Invoice.contactAddress` | L2 | `北京市朝阳区...` | `北京市*****` |
|
|
89
|
+
| `Invoice.taxId` | L3 | `91110108MA01ABC123` | `91**********23` |
|
|
90
|
+
| `Invoice.bankAccount` | L3 | `6225882104567890` | `6225********7890` |
|
|
91
|
+
| `Invoice.bankName` | L3 | `招商银行北京分行` | `招商***` |
|
|
92
|
+
| `Invoice.contactPhone` | L3 | `13800001234` | `138****1234` |
|
|
93
|
+
|
|
94
|
+
### enterprise namespace (`src/enterprise/types.ts`)
|
|
95
|
+
|
|
96
|
+
| 字段 | 级别 |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `EnterpriseSummary.contactPhone` | L3 (仅 OWNER/ADMIN 可见) |
|
|
99
|
+
| `EnterpriseSummary.contactEmail` | L3 |
|
|
100
|
+
| `EnterpriseSummary.creditCode` | L2 |
|
|
101
|
+
|
|
102
|
+
### casehall namespace (`src/casehall/types.ts`)
|
|
103
|
+
|
|
104
|
+
| 字段 | 级别 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `LawyerSummary.licenseNo` | L3 (公开 listLawyers 已脱敏剥离, 仅 admin 直读) |
|
|
107
|
+
| `LawyerSummary.idCardNo` | L3 |
|
|
108
|
+
| `LawyerSummary.realName` | L2 |
|
|
109
|
+
| `CaseLead.disputeAmountFen` | L1 |
|
|
110
|
+
| `CaseLead.contactPhone` | L3 |
|
|
111
|
+
|
|
112
|
+
## 6. 脱敏算法引用
|
|
113
|
+
|
|
114
|
+
后端 `PiiDesensitizer` (主仓 `yudao-module-distribution/...PiiDesensitizer.java`) 按字段
|
|
115
|
+
类型自动派生脱敏策略:
|
|
116
|
+
|
|
117
|
+
| 策略 | 输入 | 输出 |
|
|
118
|
+
| --- | --- | --- |
|
|
119
|
+
| `PHONE` | `13800001234` | `138****1234` |
|
|
120
|
+
| `EMAIL` | `user@acosmi.com` | `u***@acosmi.com` |
|
|
121
|
+
| `ID_CARD` | `110101199001011234` | `1101**********1234` |
|
|
122
|
+
| `BANK_CARD` | `6225882104567890` | `6225********7890` |
|
|
123
|
+
| `NAME` | `张三丰` | `张*丰` |
|
|
124
|
+
| `ADDRESS` | `北京市朝阳区...` | `北京市*****` |
|
|
125
|
+
| `GENERIC` | 任意其他 L2/L3 字符串 | `XX*****XX` (前后 2 字符+中间星号) |
|
|
126
|
+
|
|
127
|
+
`@Sensitive(strategy=...)` 显式指定策略时优先; 否则按字段名启发 (字段名含 phone/mobile
|
|
128
|
+
→ PHONE, 含 email → EMAIL, 等).
|
|
129
|
+
|
|
130
|
+
## 7. 测试集成方应做的 mock
|
|
131
|
+
|
|
132
|
+
集成方 (Web / Desktop / 微服务) 在单测中应 mock 不同角色 token 切换, 验证渲染层正确处理:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// vitest 示例 — Web 端验证 admin 视图 vs guest 视图字段差异
|
|
136
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
137
|
+
import { Client } from '@acosmi/sdk-ts';
|
|
138
|
+
|
|
139
|
+
describe('Invoice rendering across roles', () => {
|
|
140
|
+
it('platform_admin sees L3 plain', async () => {
|
|
141
|
+
// mock token 含 ROLE_PLATFORM_ADMIN claim
|
|
142
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_PLATFORM_ADMIN' }) });
|
|
143
|
+
const list = await client.listMyInvoices();
|
|
144
|
+
expect(list[0].bankAccount).toMatch(/^\d{16}$/); // 明文
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('consumer sees L3 desensitized', async () => {
|
|
148
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_CONSUMER' }) });
|
|
149
|
+
const list = await client.listMyInvoices();
|
|
150
|
+
expect(list[0].bankAccount).toMatch(/^\d{4}\*+\d{4}$/); // 6225********7890
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('guest (no token) sees L2/L3 desensitized', async () => {
|
|
154
|
+
const client = new Client({ serverURL });
|
|
155
|
+
// (公开列表端点, 无登录)
|
|
156
|
+
const lawyers = await client.listLawyers();
|
|
157
|
+
expect(lawyers.items[0].licenseNo).toBeUndefined(); // L3 直接剥字段
|
|
158
|
+
expect(lawyers.items[0].realName).toMatch(/\*/); // L2 半遮
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('ROLE_ADMIN (legacy alias) is treated as guest in v1.9.0+', async () => {
|
|
162
|
+
// 旧 yudao admin token, role=ROLE_ADMIN (无 platform_admin)
|
|
163
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_ADMIN' }) });
|
|
164
|
+
const list = await client.listMyInvoices();
|
|
165
|
+
expect(list[0].bankAccount).toMatch(/\*/); // 视同 guest, L3 脱敏
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 8. 参考链接
|
|
171
|
+
|
|
172
|
+
- 主仓 PII Aspect: `yudao-module-distribution/...impl/aspect/PiiEncryptAspect.java`
|
|
173
|
+
- 主仓角色规范化: `yudao-module-distribution/...impl/serializer/SensitiveSerializer.java`
|
|
174
|
+
- 主仓脱敏算法: `yudao-module-distribution/...impl/serializer/PiiDesensitizer.java`
|
|
175
|
+
- 主仓迁移 V51 (finance 表族加密): `nexus-v4/sql/yudao-server-v51-pii-encrypt-init.sql`
|
|
176
|
+
- 主仓迁移 V63 (列宽兜底): `nexus-v4/sql/yudao-server-v63-pii-column-text.sql`
|
|
177
|
+
- 主仓迁移 V64 (backfill): `nexus-v4/sql/yudao-server-v64-pii-backfill-v2.sql`
|
|
178
|
+
- SDK 类型注释: `src/finance/types.ts` `Invoice` JSDoc
|