GenAuth 管理 SDK
本页说明如何通过 qoni.genauth 管理用户、组织和权限,以及管理凭据、分页、响应和错误的处理规则。
待发布接口
本页对应 Qoni SDK 的 GenAuth 管理扩展。截至 2026-10-09,npm 发布版 @qoniai/qoni@0.9.0 尚未包含这组新增接口;以下示例需要包含管理扩展的 SDK 构建。正式发布版本确定后再更新安装版本。已发布的委托接口见 SDK Reference。
GenAuth 管理接口以 Authing Node SDK 4.0.2 为契约基线,提供 35 个 Namespace、591 个 JSON 管理方法名。其中 496 个来自官方 SDK,95 个是 GenAuth 扩展或兼容名称。多个方法名可能指向同一接口;部署版本、管理权限和功能开关决定实际可用范围。
前置条件与初始化
在可信 Node.js 服务端使用 Qoni AK/SK,并确认凭据绑定的 GenAuth 用户池已启用需要的管理能力。
import { Qoni } from '@qoniai/qoni'
const qoni = new Qoni({
accessKey: process.env.QONI_ACCESS_KEY!,
secretKey: process.env.QONI_SECRET_KEY!,
})
const { data: users } = await qoni.genauth.users.list({ page: 1, limit: 20 })
console.log(users.list, users.totalCount)SDK 通过 Qoni 运行时发现 GenAuth 服务,自动兑换管理 token 并缓存;并发调用共用兑换请求。管理调用使用 AK/SK 绑定的用户池,不需要用户 access token、委托 token 或 QONI_USER_ID。
| 选项 | 类型 | 说明 |
|---|---|---|
accessKey / secretKey | string | Qoni 管理凭据。只在可信服务端使用 |
host | string | 可选。私有部署的 Qoni Console / SDK gateway |
genauthHost | string | 可选。GenAuth 服务地址与自动发现结果不同时显式指定 |
timeoutMs | number | 单次 HTTP 请求超时,默认 30000 |
fetch | typeof fetch | 可选。自定义 transport |
这里的 AK/SK 是 Qoni 凭据。迁移 Authing 代码时,不要直接把 Authing 原生管理凭据当作 Qoni AK/SK。
调用方式
使用领域方法或保留 Authing 方法名,两种方式调用相同管理接口:
await qoni.genauth.groups.create({ code: 'engineering', name: 'Engineering' })
// 等价调用;创建同一个分组时只执行其中一种
// await qoni.genauth.management.createGroup({ code: 'engineering', name: 'Engineering' })
await qoni.genauth.groups.addMembers({
code: 'engineering',
userIds: ['<genauth-user-id>'],
})所有方法接收一个输入对象。Authing 的位置参数也改为具名字段,例如 management.deleteById({ id: '<id>' });SDK 负责 URL 编码和路径参数绑定。输入与返回值具有 TypeScript 类型,完整方法及类型名称见 管理方法索引。
| 参数 | 类型 | 说明 |
|---|---|---|
| 第一个参数 | 对应方法的 Input 类型 | 业务参数对象;没有必填字段的方法可省略 |
第二个参数 signal | AbortSignal | 可选。通过 { signal } 取消请求 |
adminToken / userPoolId | string | 可选。必须同时传入;覆盖自动兑换的管理凭据 |
users.*
创建、读取与更新
const { data: user } = await qoni.genauth.users.create({
username: '<unique-username>',
name: 'SDK Demo',
})
const { data: saved } = await qoni.genauth.users.get({ userId: user.userId })
await qoni.genauth.users.update({ userId: saved.userId, nickname: 'Demo' })| 方法 | 主要输入 | data |
|---|---|---|
list | page、limit、keywords、options | { list, totalCount } |
get | userId | 用户对象 |
getBatch | userIds | 用户数组 |
create | 用户字段,如 username、email、name | 用户对象 |
createBatch | list;兼容别名 users | 用户数组 |
update | userId 与需要更新的字段 | 用户对象 |
deleteBatch | userIds | 操作结果 |
iterate | 分页与筛选参数 | AsyncIterable,逐个产生用户对象 |
createBatch 同时传 list 与 users 时优先使用 list。用户名、邮箱、手机号的唯一性和创建规则由用户池配置决定。
在职用户不能直接删除。只有明确需要离职时才调用 users.resign({ userId }),随后按业务需要删除;SDK 不会自动将删除失败的用户离职。移除用户最后一个部门也可能被服务端拒绝。
分页与遍历
users.list 把顶层 page / limit 映射到 options.pagination,保留其他 options;同时传入两种分页位置时,顶层值优先。management.listUsers 使用 Authing 原始 DTO 的 options.pagination。其他列表方法使用各自的分页参数。
const { data: page } = await qoni.genauth.users.list({ page: 1, limit: 20 })
console.log(page.totalCount)
for await (const user of qoni.genauth.users.iterate({ limit: 50 })) {
console.log(user.userId)
// break 会停止遍历,不再请求下一页
}| 字段 | iterate 规则 |
|---|---|
page | 起始页,默认 1,必须为正整数 |
limit | 每页大小,默认 50,范围 1–50 |
keywords / options | 每页保留相同筛选条件 |
{ signal } | 第二个参数,取消当前请求或后续遍历 |
分页列表不是事务快照;遍历期间用户的新增或删除可能影响页面内容。
关键词与高级筛选
const { data: matches } = await qoni.genauth.users.list({
keywords: 'alice',
page: 1,
limit: 20,
options: { fuzzySearchOn: ['username', 'email'] },
})
console.log(matches.list)搜索依赖服务端索引
关键词和高级筛选走 GenAuth 搜索服务。2026-10-08 的代表性实测中,无筛选列表和按 ID 读取通过,但关键词及高级筛选未返回已创建用户;自定义字段关键词查询也出现上游错误。使用这些查询前先验证部署的搜索服务和索引。SDK 保留服务端结果和错误,不把空结果改成本地扫描结果。
角色、资源与授权
角色和资源属于已存在的权限 Namespace。用户池没有 default Namespace 时,显式创建并传入业务 Namespace;Namespace code 与应用 identifier 使用不超过 32 个字符的值。
await qoni.genauth.namespaces.create({ code: 'project', name: 'Project' })
await qoni.genauth.roles.create({
namespace: 'project', code: 'reader', name: 'Reader',
})
await qoni.genauth.roles.assign({
namespace: 'project',
code: 'reader',
targets: [{ targetType: 'USER', targetIdentifier: '<genauth-user-id>' }],
})
await qoni.genauth.resources.create({
namespace: 'project',
code: 'documents',
type: 'API',
apiIdentifier: '/documents',
actions: [{ name: 'documents:read', description: 'Read documents' }],
})
await qoni.genauth.permissions.authorize({
namespace: 'project',
list: [{
targetType: 'ROLE',
targetIdentifiers: ['reader'],
resources: [{
code: 'documents:*', resourceType: 'API', actions: ['documents:read'],
}],
}],
})
const { data: permission } = await qoni.genauth.permissions.isAllowed({
namespace: 'project',
userId: '<genauth-user-id>',
resource: 'documents:123',
action: 'documents:read',
})
console.log(permission.allowed)| 字段 | 使用位置 | 说明 |
|---|---|---|
namespace | 角色、资源、授权与判断 | 同一业务权限空间 |
type | resources.create | 资源类型;示例使用 API |
apiIdentifier | API 资源创建 | API 标识 |
resourceType | permissions.authorize 的资源项 | 授权资源类型 |
actions | 资源定义与授权 | 完整动作名,如 documents:read |
allowed | isAllowed().data | 服务端权限判断结果 |
资源定义使用 type,授权项使用 resourceType。示例会创建角色和授权,使用已有业务对象时先读取它们,避免重复创建。
自定义字段与数据
先定义字段,再设置目标对象的数据:
await qoni.genauth.customFields.set({
list: [{
targetType: 'USER', key: 'costCenter', label: 'Cost center', dataType: 'STRING',
}],
})
await qoni.genauth.customFields.setData({
targetType: 'USER',
targetIdentifier: '<genauth-user-id>',
list: [{ key: 'costCenter', value: 'engineering' }],
})
const { data: fields } = await qoni.genauth.customFields.list()
console.log(fields)| 方法 | 用途 | 主要参数 |
|---|---|---|
list | 读取字段定义 | targetType,默认 USER |
set | 创建或更新字段定义 | list 中的 targetType、key、label、dataType |
setData | 设置对象的字段值 | targetType、targetIdentifier、list |
getData | 读取对象的字段值 | targetType、targetIdentifier |
创建或更新定义时传入 dataType;已有字段的数据类型不能修改。角色字段数据还需要所属 namespace。带 keyword 的字段列表依赖搜索服务,失败处理见上方的搜索说明。
Namespace
以下 Namespace 均位于 qoni.genauth 下。完整方法名、别名和类型见 管理方法索引。
| Namespace | 用途 |
|---|---|
users | 用户、身份绑定与生命周期 |
roles | 角色及成员授权 |
groups / dynamicGroups | 静态分组与动态分组 |
organizations / departments / positions | 组织、部门与岗位 |
applications | 应用配置与访问授权 |
namespaces / resources / permissions | 权限空间、资源及权限判断 |
policies / dataPermissions | 策略与数据权限 |
tenants | 租户、成员及租户配置 |
identityProviders | 外部身份源与连接 |
customFields | 自定义字段与字段数据 |
auditLogs / sessions | 审计日志与登录会话 |
security / whitelist / riskLists | MFA、安全配置、白名单与风险名单 |
webhooks / events | Webhook 与事件 |
sync / pipelines | 同步与认证流程 |
accessKeys | 管理员访问凭据 |
publicAccounts / invitations | 公共账号与邀请 |
metadata / email / billing | 元数据、邮件与商业配置 |
devices / deviceRules | 设备与设备规则 |
approvals / ldap | 审批与 LDAP 配置 |
management | 全部 591 个平铺方法名的入口 |
management 是平铺入口,不计入 35 个领域 Namespace。旧版 GraphQL/v2、原始 makeRequest、WebSocket 辅助方法和 multipart upload 不属于这组 JSON 管理接口。
响应、取消与错误
管理方法返回 QoniResponse<T>:业务结果在 data,请求标识在 meta;users.iterate 逐个返回用户对象。
import { QoniError } from '@qoniai/qoni'
const controller = new AbortController()
try {
const { data, meta } = await qoni.genauth.roles.list(
{ namespace: 'project' },
{ signal: controller.signal },
)
console.log(data.list, meta.requestId)
} catch (error) {
if (error instanceof QoniError) {
console.error(error.status, error.code, error.requestId, error.message)
}
throw error
}调用 controller.abort() 可取消请求。管理 token 过期或被认证层拒绝时,自动兑换路径最多刷新并重试一次;权限错误、业务错误、超时和网络失败不会自动重放写操作。
| 情况 | SDK 行为 | 处理方式 |
|---|---|---|
| 缺少必填字段或覆盖凭据不完整 | QoniValidationError | 补齐参数 |
| 管理权限不足 | 抛出权限错误 | 检查管理员权限与功能开关 |
HTTP 200 但业务 statusCode >= 400 | 抛出 QoniError,不当作成功 | 按业务错误修正输入或状态 |
数字 apiCode | 保留为 error.code 字符串 | 保留错误码与请求标识用于排查 |
| 上游故障或搜索服务失败 | 抛出对应 SDK 错误,原始响应在 error.body | 检查 GenAuth 服务;不要盲目重试写操作 |
显式管理 token
已有 GenAuth 管理 token 时,在同一次调用中传入 adminToken 与 userPoolId。这组字段进入认证 header,不进入业务 payload;SDK 不刷新显式传入的 token。
const { data } = await qoni.genauth.roles.list({
namespace: 'project',
adminToken: process.env.GENAUTH_MANAGEMENT_TOKEN!,
userPoolId: process.env.GENAUTH_USERPOOL_ID!,
})
console.log(data.list)只传 userPoolId 不能切换自动兑换的用户池。目标 GenAuth 地址不同于自动发现结果时,在初始化中配置 genauthHost。