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