@h-ai/cli 0.1.0-alpha.53 → 0.1.0-alpha.55

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 (85) hide show
  1. package/README.md +18 -0
  2. package/dist/{chunk-U4PA632G.js → chunk-FVDXJYMO.js} +34 -67
  3. package/dist/chunk-FVDXJYMO.js.map +1 -0
  4. package/dist/cli-config-templates-WGN2I23J.js +5 -0
  5. package/dist/{cli-config-templates-GSXKLGU5.js.map → cli-config-templates-WGN2I23J.js.map} +1 -1
  6. package/dist/index.js +174 -105
  7. package/dist/index.js.map +1 -1
  8. package/dist/{src-QNEJJ3BV.js → src-6ZBWDBUB.js} +127 -87
  9. package/dist/{src-QNEJJ3BV.js.map → src-6ZBWDBUB.js.map} +1 -1
  10. package/package.json +13 -4
  11. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +1 -0
  12. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -0
  13. package/templates/apps/api/package.json.hbs +1 -0
  14. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +1 -0
  15. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +1 -0
  16. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +1 -0
  17. package/templates/apps/fullstack/package.json.hbs +1 -0
  18. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +1 -0
  19. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +1 -0
  20. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +1 -0
  21. package/templates/base/eslint.config.js.hbs +1 -0
  22. package/templates/base/package.json.hbs +3 -1
  23. package/templates/skills/AGENTS.md +8 -22
  24. package/templates/skills/CLAUDE.md +3 -16
  25. package/templates/skills/bridges/admin/AGENTS.md +3 -16
  26. package/templates/skills/bridges/admin/CLAUDE.md +3 -11
  27. package/templates/skills/bridges/admin/copilot-instructions.md +2 -39
  28. package/templates/skills/bridges/api/AGENTS.md +5 -18
  29. package/templates/skills/bridges/api/CLAUDE.md +3 -11
  30. package/templates/skills/bridges/api/copilot-instructions.md +3 -38
  31. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +24 -59
  32. package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +1 -15
  33. package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -45
  34. package/templates/skills/bridges/h5/AGENTS.md +4 -17
  35. package/templates/skills/bridges/h5/CLAUDE.md +3 -11
  36. package/templates/skills/bridges/h5/copilot-instructions.md +2 -37
  37. package/templates/skills/bridges/mobile-app/AGENTS.md +5 -18
  38. package/templates/skills/bridges/mobile-app/CLAUDE.md +3 -11
  39. package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -38
  40. package/templates/skills/bridges/website/AGENTS.md +4 -17
  41. package/templates/skills/bridges/website/CLAUDE.md +3 -11
  42. package/templates/skills/bridges/website/copilot-instructions.md +2 -37
  43. package/templates/skills/copilot-instructions.md +2 -36
  44. package/templates/skills/hai-ai/SKILL.md +35 -389
  45. package/templates/skills/hai-ai/guide.md +383 -0
  46. package/templates/skills/hai-ai/reference.md +6 -2
  47. package/templates/skills/hai-api-client/SKILL.md +6 -6
  48. package/templates/skills/hai-api-contract/SKILL.md +10 -25
  49. package/templates/skills/hai-app-create/SKILL.md +29 -388
  50. package/templates/skills/hai-app-create/reference.md +350 -0
  51. package/templates/skills/hai-app-review/SKILL.md +15 -23
  52. package/templates/skills/hai-app-tests/SKILL.md +29 -494
  53. package/templates/skills/hai-app-tests/reference.md +442 -0
  54. package/templates/skills/hai-audit/SKILL.md +6 -6
  55. package/templates/skills/hai-build/SKILL.md +19 -330
  56. package/templates/skills/hai-build/reference.md +326 -0
  57. package/templates/skills/hai-cache/SKILL.md +28 -31
  58. package/templates/skills/hai-capacitor/SKILL.md +19 -364
  59. package/templates/skills/hai-capacitor/reference.md +352 -0
  60. package/templates/skills/hai-ci/SKILL.md +17 -20
  61. package/templates/skills/hai-core/SKILL.md +25 -564
  62. package/templates/skills/hai-core/reference.md +533 -0
  63. package/templates/skills/hai-crypto/SKILL.md +8 -20
  64. package/templates/skills/hai-datapipe/SKILL.md +9 -23
  65. package/templates/skills/hai-deploy/SKILL.md +18 -24
  66. package/templates/skills/hai-framework-sync/SKILL.md +8 -20
  67. package/templates/skills/hai-iam/SKILL.md +27 -365
  68. package/templates/skills/hai-iam/reference.md +343 -0
  69. package/templates/skills/hai-kit/SKILL.md +6 -6
  70. package/templates/skills/hai-payment/SKILL.md +6 -26
  71. package/templates/skills/hai-pr-review/SKILL.md +6 -22
  72. package/templates/skills/hai-reach/SKILL.md +19 -317
  73. package/templates/skills/hai-reach/reference.md +303 -0
  74. package/templates/skills/hai-reldb/SKILL.md +19 -472
  75. package/templates/skills/hai-reldb/reference.md +452 -0
  76. package/templates/skills/hai-scheduler/SKILL.md +18 -6
  77. package/templates/skills/hai-serv/SKILL.md +27 -759
  78. package/templates/skills/hai-serv/reference.md +736 -0
  79. package/templates/skills/hai-storage/SKILL.md +7 -25
  80. package/templates/skills/hai-ui/SKILL.md +29 -621
  81. package/templates/skills/hai-ui/reference.md +598 -0
  82. package/templates/skills/hai-vecdb/SKILL.md +18 -303
  83. package/templates/skills/hai-vecdb/reference.md +291 -0
  84. package/dist/chunk-U4PA632G.js.map +0 -1
  85. package/dist/cli-config-templates-GSXKLGU5.js +0 -5
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hai-iam
3
- description: 使用 @h-ai/iam 进行身份认证(密码/OTP/LDAP/API Key)、统一 Bearer Token 管理(TokenPair/refresh/revoke)与 RBAC 授权;当需求涉及登录、注册、权限检查、角色管理、Token 认证或通过 @h-ai/api-contract 暴露 IAM API 时使用。
3
+ description: "使用 @h-ai/iam 实现登录、注册、会话、OTP/LDAP/API Key 和 RBAC。"
4
4
  ---
5
5
 
6
6
  # hai-iam
@@ -9,367 +9,29 @@ description: 使用 @h-ai/iam 进行身份认证(密码/OTP/LDAP/API Key)、
9
9
 
10
10
  | 项目 | 契约 |
11
11
  | --- | --- |
12
- | 能力 | 使用 @h-ai/iam 进行身份认证(密码/OTP/LDAP/API Key)、统一 Bearer Token 管理(TokenPair/refresh/revoke)与 RBAC 授权;当需求涉及登录、注册、权限检查、角色管理、Token 认证或通过 @h-ai/api-contract 暴露 IAM API 时使用。 |
13
- | 适用场景 | 当任务与 `hai-iam` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
14
- | 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
15
- | 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
16
- | 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
17
-
18
- > `@h-ai/iam` 是统一的身份与访问管理模块,支持多种认证策略(密码/OTP/LDAP/API Key)、Bearer Token 管理和 RBAC 授权。依赖 `@h-ai/reldb`(持久化)、`@h-ai/cache`(Token + 权限缓存)、`@h-ai/crypto`(密码哈希)、`@h-ai/audit`(审计日志)。
19
-
20
- ---
21
-
22
- ## 运行环境
23
-
24
- > ⚠️ **服务端模块(Node.js only)。** 浏览器端通过 `@h-ai/api-client` 的 typed client 调用 IAM API,例如 `apiClient.iam.auth.login()`。HTTP 契约统一来自 `@h-ai/api-contract`。
25
-
26
- ---
27
-
28
- ## 依赖
29
-
30
- | 模块 | 用途 | 是否必需 | 初始化要求 |
31
- | --- | --- | --- | --- |
32
- | `@h-ai/reldb` | 数据库(用户/角色/权限持久化) | **必需** | 需在 `iam.init()` 前初始化 |
33
- | `@h-ai/cache` | 缓存(会话/OTP/重置令牌/权限缓存) | **必需** | 需在 `iam.init()` 前初始化 |
34
- | `@h-ai/crypto` | 密码哈希 | 内部使用 | 自动初始化 |
35
- | `@h-ai/audit` | 审计日志(RBAC 关键操作记录) | 内部使用 | 已初始化时自动写入 |
36
-
37
- ## 适用场景
38
-
39
- - 用户注册与登录(密码/OTP/LDAP/API Key)
40
- - Bearer Token 认证与管理(TokenPair: accessToken + refreshToken)
41
- - Token 刷新(rotation 策略)与吊销
42
- - RBAC 角色/权限的创建、分配与检查
43
- - API Key 管理(创建、吊销、验证)
44
- - 密码重置流程
45
- - 与 kit 集成的认证守卫
46
- - 通过 `@h-ai/api-contract` 暴露 IAM HTTP contract
47
-
48
- ---
49
-
50
- ## 使用步骤
51
-
52
- ### 1. 配置
53
-
54
- ```yaml
55
- # config/_iam.yml
56
- password:
57
- minLength: 8
58
- requireUppercase: true
59
- requireNumber: true
60
- session:
61
- maxAge: 86400
62
- refreshTokenMaxAge: 604800 # 7 天
63
- sliding: true
64
- singleDevice: false
65
- login:
66
- password: true
67
- otp: false
68
- register:
69
- enabled: true
70
- security:
71
- maxLoginAttempts: 5
72
- lockoutDuration: 900
73
- rbac:
74
- defaultRole: user
75
- superAdminRole: super_admin
76
- ```
77
-
78
- 约定环境变量优先于 YAML,例如 `HAI_IAM_PASSWORD_MINLENGTH`、
79
- `HAI_IAM_SESSION_MAXAGE`、`HAI_IAM_SECURITY_MAXLOGINATTEMPTS`。
80
-
81
- ### 2. 初始化
82
-
83
- ```typescript
84
- import { cache } from '@h-ai/cache'
85
- import { reldb } from '@h-ai/reldb'
86
- import { iam } from '@h-ai/iam'
87
-
88
- // 必须先初始化 reldb 和 cache
89
- await reldb.init(core.config.get('db'))
90
- await cache.init(core.config.get('cache'))
91
-
92
- // IAM 自动使用已初始化的 reldb 和 cache 单例
93
- await iam.init({
94
- ...core.config.get('iam'),
95
- seedDefaultData: true,
96
- })
97
- ```
98
-
99
- `iam.config` 返回的是脱敏后的配置快照;LDAP `url` / `bindPassword` 等敏感值会自动隐藏。
100
-
101
- 初始化时自动创建数据库表(5 张):`hai_iam_users`、`hai_iam_roles`、`hai_iam_permissions`、`hai_iam_role_permissions`、`hai_iam_user_roles`。
102
-
103
- Token 和 OTP 存储在 cache 中(不落库)。refreshToken 使用独立的 cache key 存储。
104
-
105
- ---
106
-
107
- ## 核心 API
108
-
109
- ### 认证 — `iam.auth`
110
-
111
- | 方法 | 签名 | 说明 |
112
- | ------------------ | ----------------------------------------------------------- | ---------------------------------- |
113
- | `login` | `({ identifier, password }) => Promise<HaiResult<AuthResult>>` | 密码登录(用户名/邮箱/手机号) |
114
- | `loginWithOtp` | `({ identifier, code }) => Promise<HaiResult<AuthResult>>` | OTP 验证码登录 |
115
- | `loginWithLdap` | `({ username, password }) => Promise<HaiResult<AuthResult>>` | LDAP 登录 |
116
- | `loginWithApiKey` | `({ key }) => Promise<HaiResult<AuthResult>>` | API Key 登录 |
117
- | `sendOtp` | `(identifier) => Promise<HaiResult<{ expiresAt }>>` | 发送 OTP 验证码 |
118
- | `verifyToken` | `(token) => Promise<HaiResult<Session>>` | 验证令牌(推荐入口,委托 session) |
119
- | `logout` | `(token) => Promise<HaiResult<void>>` | 登出 |
120
- | `registerAndLogin` | `(options: RegisterOptions) => Promise<HaiResult<AuthResult>>` | 注册并登录(一站式) |
121
-
122
- **AuthResult**(已改造为 TokenPair):
123
-
124
- ```typescript
125
- interface AuthResult {
126
- user: User
127
- tokens: TokenPair
128
- roles: string[]
129
- permissions: string[]
130
- agreements?: AgreementDisplay
131
- }
132
-
133
- interface TokenPair {
134
- accessToken: string
135
- refreshToken: string
136
- expiresIn: number
137
- tokenType: 'Bearer'
138
- }
139
- ```
140
-
141
- ### 会话管理 — `iam.session`
142
-
143
- | 方法 | 签名 | 说明 |
144
- | ------------------- | -------------------------------------------------------------------- | --------------------------------------- |
145
- | `create` | `({ userId, username, roles, source? }) => Promise<HaiResult<Session>>` | 创建会话(返回含 TokenPair 的 session) |
146
- | `get` | `(token) => Promise<HaiResult<Session \| null>>` | 获取会话(滑动续期自动延长) |
147
- | `verifyToken` | `(token) => Promise<HaiResult<Session>>` | 验证令牌 |
148
- | `update` | `(token, data) => Promise<HaiResult<void>>` | 更新会话字段(浅合并 data) |
149
- | `delete` | `(token) => Promise<HaiResult<void>>` | 删除会话 |
150
- | `deleteByUserId` | `(userId) => Promise<HaiResult<number>>` | 删除用户所有会话(返回删除数量) |
151
- | `refresh` | `(refreshToken) => Promise<HaiResult<TokenPair>>` | 刷新 Token(rotation:旧 Token 失效) |
152
- | `revokeRefresh` | `(refreshToken) => Promise<HaiResult<void>>` | 吊销 refreshToken |
153
- | `patchUserSessions` | `(userId, updates: SessionFieldUpdates) => Promise<HaiResult<void>>` | 批量更新用户所有会话的 roles/permissions |
154
-
155
- **Token 刷新(rotation 策略)**:
156
-
157
- - `refresh()` 会删除旧的 accessToken + refreshToken
158
- - 创建全新的 session,返回新的 TokenPair
159
- - 旧 refreshToken 立即失效,防止重放攻击
160
-
161
- ### 一次性票据 — `iam.ticket`
162
-
163
- 短期、一次性能力票据,用于无法携带 Bearer Token 的通道(如 WebSocket URL)。密码学安全随机、TTL、原子单次消费、用途绑定。
164
-
165
- | 方法 | 签名 | 说明 |
166
- | ---------- | -------------------------------------------------------------------------------------- | ------------------------------------- |
167
- | `issue` | `({ subjectId, purpose, grant?, ttlMs? }) => Promise<HaiResult<{ ticket, expiresAt }>>` | 签发(默认 30s) |
168
- | `consume` | `(ticket, { purpose? }?) => Promise<HaiResult<{ subjectId, purpose, grant }>>` | 原子消费(单次有效,用途不符拒绝) |
169
-
170
- ```ts
171
- const issued = await iam.ticket.issue({ subjectId, purpose: 'ai-audio', grant: { operation: 'transcribe' } })
172
- const consumed = await iam.ticket.consume(ticket, { purpose: 'ai-audio' }) // 并发消费仅一个成功
173
- ```
174
-
175
- 错误码:`TICKET_INVALID`(hai:iam:110) / `TICKET_EXPIRED`(hai:iam:111) / `TICKET_ISSUE_FAILED`(hai:iam:112)。
176
-
177
- ### 用户管理 — `iam.user`
178
-
179
- | 方法 | 签名 | 说明 |
180
- | -------------------------- | ----------------------------------------------------------------------- | ------------------------------------ |
181
- | `register` | `(input) => Promise<HaiResult<RegisterResult>>` | 用户注册 |
182
- | `getUser` | `(id, options?) => Promise<HaiResult<User \| null>>` | 获取用户(可选 include: ['roles']) |
183
- | `getCurrentUser` | `(token) => Promise<HaiResult<User>>` | 通过令牌获取当前用户 |
184
- | `updateCurrentUser` | `(token, data: UpdateCurrentUserInput) => Promise<HaiResult<User>>` | 当前用户修改个人资料(白名单字段) |
185
- | `listUsers` | `(options?: ListUsersOptions) => Promise<HaiResult<PaginatedResult<User>>>` | 用户列表(分页 + 搜索 + 过滤 + 白名单排序) |
186
- | `updateUser` | `(id, data) => Promise<HaiResult<User>>` | 更新用户信息 |
187
- | `deleteUser` | `(id) => Promise<HaiResult<void>>` | 删除用户(自动清除会话) |
188
- | `changePassword` | `(id, old, new) => Promise<HaiResult<void>>` | 修改密码(自动清除会话) |
189
- | `changeCurrentUserPassword`| `(token, old, new) => Promise<HaiResult<void>>` | 当前用户修改密码(通过令牌识别) |
190
- | `requestPasswordReset` | `(email) => Promise<HaiResult<void>>` | 请求密码重置(防枚举) |
191
- | `confirmPasswordReset` | `(token, newPassword) => Promise<HaiResult<void>>` | 确认密码重置(自动清除会话) |
192
- | `adminResetPassword` | `(userId, newPassword) => Promise<HaiResult<void>>` | 管理员直接重置密码 |
193
- | `validatePassword` | `(password) => HaiResult<void>` | 验证密码强度(**同步方法**) |
194
-
195
- ### RBAC 授权 — `iam.authz`
196
-
197
- | 方法 | 签名 | 说明 |
198
- | -------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------- |
199
- | `checkPermission` | `(userId, permission) => Promise<HaiResult<boolean>>` | 检查权限(超管自动通过,支持通配符) |
200
- | `getUserPermissions` | `(userId) => Promise<HaiResult<Permission[]>>` | 获取用户权限列表(通过角色聚合去重) |
201
- | `getUserRoles` | `(userId) => Promise<HaiResult<Role[]>>` | 获取用户角色列表 |
202
- | `getUserRolesForMany` | `(userIds) => Promise<HaiResult<Map<string, Role[]>>>` | 批量获取多用户角色(避免 N+1) |
203
- | `assignRole` | `(userId, roleId, tx?) => Promise<HaiResult<void>>` | 分配角色给用户 |
204
- | `removeRole` | `(userId, roleId, tx?) => Promise<HaiResult<void>>` | 移除用户角色 |
205
- | `syncRoles` | `(userId, roleIds, tx?) => Promise<HaiResult<void>>` | 同步用户角色(替换为目标列表) |
206
- | `createRole` | `({ code, name, description? }, tx?) => Promise<HaiResult<Role>>` | 创建角色 |
207
- | `getRole` | `(roleId) => Promise<HaiResult<Role \| null>>` | 获取角色 |
208
- | `getRoleByCode` | `(code) => Promise<HaiResult<Role \| null>>` | 根据代码获取角色 |
209
- | `getAllRoles` | `(options?) => Promise<HaiResult<PaginatedResult<Role>>>` | 获取所有角色(分页) |
210
- | `updateRole` | `(roleId, data, tx?) => Promise<HaiResult<Role>>` | 更新角色 |
211
- | `deleteRole` | `(roleId, tx?) => Promise<HaiResult<void>>` | 删除角色(级联清理关联 + 会话同步) |
212
- | `createPermission` | `({ code, name, type?, resource?, action? }, tx?) => Promise<HaiResult<Permission>>`| 创建权限 |
213
- | `getPermission` | `(permissionId) => Promise<HaiResult<Permission \| null>>` | 获取权限 |
214
- | `getPermissionByCode` | `(code) => Promise<HaiResult<Permission \| null>>` | 根据代码获取权限 |
215
- | `getAllPermissions` | `(options?: PermissionQueryOptions) => Promise<HaiResult<PaginatedResult<Permission>>>` | 获取所有权限(分页 + 类型/关键字筛选) |
216
- | `deletePermission` | `(permissionId, tx?) => Promise<HaiResult<void>>` | 删除权限(级联清理关联 + 会话同步) |
217
- | `assignPermissionToRole` | `(roleId, permId, tx?) => Promise<HaiResult<void>>` | 分配权限给角色 |
218
- | `removePermissionFromRole` | `(roleId, permId, tx?) => Promise<HaiResult<void>>` | 移除角色权限 |
219
- | `getRolePermissions` | `(roleId) => Promise<HaiResult<Permission[]>>` | 获取角色的权限列表 |
220
- | `getRolePermissionsForMany`| `(roleIds) => Promise<HaiResult<Map<string, Permission[]>>>` | 批量获取多角色权限(避免 N+1) |
221
-
222
- **通配符规则**:`admin:*` 匹配 `admin:read`、`admin:write` 等。超管角色自动拥有所有权限。
223
-
224
- ### API Key 管理 — `iam.apiKey`
225
-
226
- | 方法 | 签名 | 说明 |
227
- | -------------- | ----------------------------------------------------------------------- | -------------------------------------- |
228
- | `createApiKey` | `(userId, options: CreateApiKeyOptions) => Promise<HaiResult<CreateApiKeyResult>>` | 创建 API Key(明文密钥仅返回一次) |
229
- | `listApiKeys` | `(userId, options?) => Promise<HaiResult<PaginatedResult<ApiKey>>>` | 分页列出用户的 API Key |
230
- | `getApiKey` | `(keyId) => Promise<HaiResult<ApiKey \| null>>` | 获取 API Key 详情 |
231
- | `revokeApiKey` | `(keyId) => Promise<HaiResult<void>>` | 吊销/删除 API Key |
232
- | `verifyApiKey` | `(rawKey) => Promise<HaiResult<ApiKey>>` | 验证 API Key 并返回实体(含用户 ID) |
233
-
234
- > 需在 `login.apikey: true` 时才会初始化此子模块,否则访问返回 `NOT_INITIALIZED` 错误。
235
-
236
- ---
237
-
238
- ## HTTP API 契约
239
-
240
- IAM HTTP API 统一由 `@h-ai/api-contract` 的 `apiContract.iam` 定义,由 `@h-ai/serv/features/iam` 绑定到本模块。
241
-
242
- ```typescript
243
- import { apiClient } from '@h-ai/api-client'
244
-
245
- const result = await apiClient.iam.auth.login({ identifier: username, password })
246
- ```
247
-
248
- ---
249
-
250
- ## 错误码 — `HaiIamError`
251
-
252
- | 错误码 | code | 说明 |
253
- |--------|------|------|
254
- | `HaiIamError.AUTH_FAILED` | `hai:iam:001` | 认证失败 |
255
- | `HaiIamError.INVALID_CREDENTIALS` | `hai:iam:002` | 凭证无效 |
256
- | `HaiIamError.USER_NOT_FOUND` | `hai:iam:003` | 用户不存在 |
257
- | `HaiIamError.USER_DISABLED` | `hai:iam:004` | 用户已禁用 |
258
- | `HaiIamError.USER_LOCKED` | `hai:iam:005` | 用户已锁定 |
259
- | `HaiIamError.USER_ALREADY_EXISTS` | `hai:iam:006` | 用户已存在 |
260
- | `HaiIamError.PASSWORD_EXPIRED` | `hai:iam:007` | 密码已过期 |
261
- | `HaiIamError.PASSWORD_POLICY_VIOLATION` | `hai:iam:008` | 密码不符合策略 |
262
- | `HaiIamError.OTP_INVALID` | `hai:iam:009` | 验证码无效 |
263
- | `HaiIamError.NOT_INITIALIZED` | `hai:iam:010` | 未初始化 |
264
- | `HaiIamError.OTP_RESEND_TOO_FAST` | `hai:iam:011` | 发送过于频繁 |
265
- | `HaiIamError.LOGIN_DISABLED` | `hai:iam:012` | 登录方式已禁用 |
266
- | `HaiIamError.REGISTER_DISABLED` | `hai:iam:013` | 注册已禁用 |
267
- | `HaiIamError.STRATEGY_NOT_SUPPORTED` | `hai:iam:014` | 认证策略不支持 |
268
- | `HaiIamError.APIKEY_INVALID` | `hai:iam:015` | API Key 无效 |
269
- | `HaiIamError.APIKEY_EXPIRED` | `hai:iam:016` | API Key 已过期 |
270
- | `HaiIamError.APIKEY_DISABLED` | `hai:iam:017` | API Key 已禁用 |
271
- | `HaiIamError.APIKEY_NOT_FOUND` | `hai:iam:018` | API Key 不存在 |
272
- | `HaiIamError.RESET_TOKEN_INVALID` | `hai:iam:019` | 重置令牌无效 |
273
- | `HaiIamError.RESET_TOKEN_EXPIRED` | `hai:iam:020` | 重置令牌已过期 |
274
- | `HaiIamError.RESET_TOKEN_MAX_ATTEMPTS` | `hai:iam:021` | 重置验证次数超限 |
275
- | `HaiIamError.OTP_EXPIRED` | `hai:iam:022` | 验证码已过期 |
276
- | `HaiIamError.SESSION_NOT_FOUND` | `hai:iam:101` | 会话不存在 |
277
- | `HaiIamError.SESSION_EXPIRED` | `hai:iam:102` | 会话已过期 |
278
- | `HaiIamError.SESSION_INVALID` | `hai:iam:103` | 会话无效 |
279
- | `HaiIamError.SESSION_CREATE_FAILED` | `hai:iam:104` | 会话创建失败 |
280
- | `HaiIamError.TOKEN_EXPIRED` | `hai:iam:105` | 令牌已过期 |
281
- | `HaiIamError.TOKEN_INVALID` | `hai:iam:106` | 令牌无效 |
282
- | `HaiIamError.TOKEN_REFRESH_FAILED` | `hai:iam:107` | 令牌刷新失败 |
283
- | `HaiIamError.PERMISSION_DENIED` | `hai:iam:201` | 权限不足 |
284
- | `HaiIamError.ROLE_NOT_FOUND` | `hai:iam:202` | 角色不存在 |
285
- | `HaiIamError.PERMISSION_NOT_FOUND` | `hai:iam:203` | 权限不存在 |
286
- | `HaiIamError.ROLE_ALREADY_EXISTS` | `hai:iam:204` | 角色已存在 |
287
- | `HaiIamError.PERMISSION_ALREADY_EXISTS` | `hai:iam:205` | 权限已存在 |
288
- | `HaiIamError.LDAP_CONNECTION_FAILED` | `hai:iam:301` | LDAP 连接失败 |
289
- | `HaiIamError.LDAP_BIND_FAILED` | `hai:iam:302` | LDAP 绑定失败 |
290
- | `HaiIamError.LDAP_SEARCH_FAILED` | `hai:iam:303` | LDAP 搜索失败 |
291
- | `HaiIamError.REPOSITORY_ERROR` | `hai:iam:401` | 存储层操作错误 |
292
- | `HaiIamError.NOT_FOUND` | `hai:iam:402` | 资源不存在 |
293
- | `HaiIamError.CONFLICT` | `hai:iam:403` | 资源冲突 |
294
- | `HaiIamError.FORBIDDEN` | `hai:iam:501` | 禁止访问 |
295
- | `HaiIamError.INVALID_ARGUMENT` | `hai:iam:502` | 参数无效 |
296
- | `HaiIamError.CONFIG_ERROR` | `hai:iam:901` | 配置错误 |
297
- | `HaiIamError.INTERNAL_ERROR` | `hai:iam:999` | 内部错误 |
298
-
299
- ---
300
-
301
- ## 常见模式
302
-
303
- ### 与 kit 集成(hooks.server.ts)
304
-
305
- ```typescript
306
- import { iam } from '$lib/server/init'
307
- import { kit } from '@h-ai/kit'
308
-
309
- const haiHandle = kit.createHandle({
310
- validateSession: async (token) => {
311
- const result = await iam.auth.verifyToken(token)
312
- if (!result.success)
313
- return null
314
- const roles = await iam.authz.getUserRoles(result.data.userId)
315
- return {
316
- userId: result.data.userId,
317
- roles: roles.success ? roles.data.map(r => r.code) : [],
318
- permissions: [],
319
- }
320
- },
321
- guards: [
322
- {
323
- guard: kit.guard.auth({ apiMode: true }),
324
- paths: ['/api/*'],
325
- exclude: ['/api/auth/*'],
326
- },
327
- ],
328
- })
329
-
330
- export const handle = kit.sequence(haiHandle)
331
- ```
332
-
333
- ### 客户端认证流程
334
-
335
- ```typescript
336
- // 登录 → 保存 Token
337
- const login = await apiClient.iam.auth.login({ identifier: username, password })
338
- if (login.success) {
339
- await apiClient.auth.setTokens(login.data.tokens)
340
- }
341
-
342
- // 获取当前用户
343
- const me = await apiClient.iam.auth.currentUser()
344
- if (me.success) {
345
- // 返回 User + 服务端当前会话的 roles/permissions。
346
- // 身份资料与访问范围可在状态层拆开,但不要持久化权限快照。
347
- const { roles, permissions, ...user } = me.data
348
- }
349
-
350
- // Token 过期时,api-client 自动调用 refreshPath 刷新
351
- // 刷新失败时,清除 Token 并跳转登录页
352
-
353
- // 登出
354
- await apiClient.iam.auth.logout({})
355
- await apiClient.auth.clear()
356
- ```
357
-
358
- ### 自动会话失效
359
-
360
- 以下操作自动清除受影响用户的所有活跃会话:
361
-
362
- - `deleteUser` / `updateUser({ enabled: false })` / `changePassword` / `confirmPasswordReset`
363
- - `assignRole` / `removeRole` / `deleteRole` 会同步更新活跃会话中的角色列表
364
-
365
- ---
366
-
367
- ## 相关 Skills
368
-
369
- - `hai-build`:模块初始化顺序(db → cache → iam)
370
- - `hai-kit`:SvelteKit 集成(Bearer Token + 契约处理)
371
- - `hai-api-client`:客户端契约调用
372
- - `hai-reldb`:底层数据存储
373
- - `hai-cache`:Token 与权限缓存
374
- - `hai-crypto`:密码哈希(内部依赖)
375
- - `hai-ui`:IAM 场景组件(LoginForm/RegisterForm 等)
12
+ | 能力 | 使用 @h-ai/iam 实现登录、注册、会话、OTP/LDAP/API Key 和 RBAC |
13
+ | 适用场景 | 应用身份认证、会话失效或角色权限管理 |
14
+ | 输入 | IamConfigInput、已初始化依赖、凭据、用户/角色/权限 ID |
15
+ | 输出 | 认证、会话与授权操作的 HaiResult |
16
+ | 限制 | 仅服务端,先初始化 reldb/cache(crypto 未初始化时由 IAM 初始化);公开认证入口是 iam.auth。客户端经 contract/API 调用,不能暴露密码或完整 token。 |
17
+
18
+ ## 使用路径
19
+
20
+ - `_iam.yml` 只传 IamConfigInput;不把 reldb/cache 句柄混入配置。
21
+ - 角色资料与 permissionIds 一次保存:未传保持、空数组清空、未知 ID 失败;人数查询失败不能显示为 0。
22
+ - IAM 服务端是 iam.auth;typed HTTP client 的路径是 apiClient.iam.auth。
23
+ - OTP/API Key 等先核对 login 开关;不把未启用能力的 NOT_INITIALIZED 当认证失败。
24
+
25
+ ## 按需参考
26
+
27
+ 详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
28
+
29
+ - 运行环境
30
+ - 依赖
31
+ - 适用场景
32
+ - 使用步骤
33
+ - 核心 API
34
+ - HTTP API 契约
35
+ - 错误码 — `HaiIamError`
36
+ - 常见模式
37
+ - 相关 Skills