跳到正文

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 用户池已启用需要的管理能力。

ts
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 / secretKeystringQoni 管理凭据。只在可信服务端使用
hoststring可选。私有部署的 Qoni Console / SDK gateway
genauthHoststring可选。GenAuth 服务地址与自动发现结果不同时显式指定
timeoutMsnumber单次 HTTP 请求超时,默认 30000
fetchtypeof fetch可选。自定义 transport

这里的 AK/SK 是 Qoni 凭据。迁移 Authing 代码时,不要直接把 Authing 原生管理凭据当作 Qoni AK/SK。

调用方式 ​

使用领域方法或保留 Authing 方法名,两种方式调用相同管理接口:

ts
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 类型业务参数对象;没有必填字段的方法可省略
第二个参数 signalAbortSignal可选。通过 { signal } 取消请求
adminToken / userPoolIdstring可选。必须同时传入;覆盖自动兑换的管理凭据

users.* ​

创建、读取与更新 ​

ts
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
listpage、limit、keywords、options{ list, totalCount }
getuserId用户对象
getBatchuserIds用户数组
create用户字段,如 username、email、name用户对象
createBatchlist;兼容别名 users用户数组
updateuserId 与需要更新的字段用户对象
deleteBatchuserIds操作结果
iterate分页与筛选参数AsyncIterable,逐个产生用户对象

createBatch 同时传 list 与 users 时优先使用 list。用户名、邮箱、手机号的唯一性和创建规则由用户池配置决定。

在职用户不能直接删除。只有明确需要离职时才调用 users.resign({ userId }),随后按业务需要删除;SDK 不会自动将删除失败的用户离职。移除用户最后一个部门也可能被服务端拒绝。

分页与遍历 ​

users.list 把顶层 page / limit 映射到 options.pagination,保留其他 options;同时传入两种分页位置时,顶层值优先。management.listUsers 使用 Authing 原始 DTO 的 options.pagination。其他列表方法使用各自的分页参数。

ts
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 }第二个参数,取消当前请求或后续遍历

分页列表不是事务快照;遍历期间用户的新增或删除可能影响页面内容。

关键词与高级筛选 ​

ts
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 个字符的值。

ts
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角色、资源、授权与判断同一业务权限空间
typeresources.create资源类型;示例使用 API
apiIdentifierAPI 资源创建API 标识
resourceTypepermissions.authorize 的资源项授权资源类型
actions资源定义与授权完整动作名,如 documents:read
allowedisAllowed().data服务端权限判断结果

资源定义使用 type,授权项使用 resourceType。示例会创建角色和授权,使用已有业务对象时先读取它们,避免重复创建。

自定义字段与数据 ​

先定义字段,再设置目标对象的数据:

ts
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 / riskListsMFA、安全配置、白名单与风险名单
webhooks / eventsWebhook 与事件
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 逐个返回用户对象。

ts
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。

ts
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。

下一步 ​