跳转至

用户导入 API

用户导入 API 支持将用户从其他系统批量导入到 Authany 项目。该 API 不属于 Admin API GraphQL 的一部分。不过,访问该 API 端点仍需要 Admin API JWT 令牌。

以下是关于用户导入 API 的其他重要说明:

  • 实际的用户导入过程是异步的,即执行在后台完成。API 提供了一个端点,供开发者查询导入的状态。
  • 导入任务成功发起后,API 会返回该任务的 ID。查询导入状态时需要用到这个 ID。
  • 发送给该 API 的 HTTP 请求正文大小限制为 500KB。
  • 使用用户导入 API 不会触发 user.pre_create 和 user.created Hook。
  • 该 API 支持 Bcrypt 密码格式。要以此格式导入密码,需要在作为用户 password 字段值的对象中指定 type 和 password_hash。例如:
"password": {
        "type": "bcrypt",
        "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
      },

端点

导入用户 API 提供两个端点,一个用于发起用户导入任务,另一个用于查询任务状态。这些端点仅支持安全的 HTTPS 请求,并要求通过 Bearer 授权请求头(Authorization: Bearer <Admin API JWT Token>)提供有效的 Admin API JWT 令牌。

Run In Postman

以下是这些端点及其预期输入的更多详情。

发起导入

POST /_api/admin/users/import

使用此端点创建新的用户导入任务。

请求头

名称 值
Content-Type application/json
Authorization Bearer <Admin API JWT Token>
Host <Your Authgear Project Domain>

请求体

发起导入端点通过 HTTP(S) 请求体接受 JSON 输入。以下是输入示例:

{
    "identifier": "email",
    "records": [
        {
            "email": "user@example.com",
            "email_verified": true,
            "password": {
                "type": "bcrypt",
                "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
            }
        }
    ]
}

输入格式

用于发起导入的端点通过 HTTP 请求体接受 JSON 输入。以下示例 JSON 文档展示了输入的预期结构和字段:

{
  "upsert": true,
  "identifier": "email",
  "records": [
    {
      "preferred_username": "jdoe",
      "email": "johndoe@example.com",
      "phone_number": "+85123456789",

      "email_verified": true,
      "phone_number_verified": true,

      "name": "John Doe",
      "given_name": "John",
      "family_name": "Doe",
      "middle_name": "",
      "nickname": "JD",
      "profile": "https://example.com",
      "picture": "https://example.com",
      "website": "https://example.com",
      "gender": "male",
      "birthdate": "1990-01-01",
      "zoneinfo": "Asia/Hong_Kong",
      "locale": "zh-Hant-HK",
      "address": {
        "formatted": "1 Unnamed Road, Central, Hong Kong Island, HK",
        "street_address": "1 Unnamed Road",
        "locality": "Central",
        "region": "Hong Kong",
        "postal_code": "N/A",
        "country": "HK"
      },

      "custom_attributes": {
        "member_id": "123456789"
      },

      "roles": ["role_a", "role_b"],
      "groups": ["group_a"],

      "disabled": false,

      "password": {
        "type": "bcrypt",
        "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
      },

      "mfa": {
        "email": "johndoe@example.com",
        "phone_number": "+85123456789",
        "password": {
          "type": "bcrypt",
          "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
        },
        "totp": {
          "secret": "secret"
        }
      }
    }
  ]
}

为了更好地理解输入内容,我们来仔细看看上述 JSON 文档根节点上直接包含的三个字段(upsert、identifier、records)。

  • upsert:这是一个可选的布尔值,默认值为 false。当该字段的值设为 true,且已存在具有相同身份标识的用户时,系统会根据每个属性的更新行为更新该用户的数据。
  • identifier:该字段为必填项。它告诉 Authany 使用哪个属性来识别已存在的用户。可接受的值为以下字符串:preferred_username、email 和 phone_number。
  • records:开发者可以在此以数组形式提供希望导入的所有用户数据。数组中的每个直接对象代表一个用户。在对象内部,您可以使用如上例所示的各个字段来定义该用户的标准属性。您也可以像上例中那样,在嵌套于 custom_attributes 字段内的对象中定义自定义属性。

响应

{
  "id": "task_4WZ0V7EPT4GZ2ABVN03QXYZ122W835C1",
  "created_at": "2024-04-04T06:56:36.02508096Z",
  "status": "pending"
}
{
  "error": "Invalid request"
}

id:这是所创建导入任务的唯一 ID。查询任务状态时需要用到该 ID。

status:导入任务创建后,status 的值为 pending;用户导入任务完成后,值为 completed。

查询状态

GET /_api/admin/users/import/{ID}

使用此端点查询现有用户导入任务的状态。请将 {ID} 替换为有效的用户导入任务 ID。

请求头

名称 值
Authorization Bearer <Admin API JWT Token>
Host <Your Authgear Project Domain>

响应

{
  "id": "task_4WZ0V7EPT4GZ2ABVN03QXYZ122W835C1",
  "created_at": "2024-04-04T06:56:36.02508096Z",
  "status": "completed",
  "summary": {
    "total": 2,
    "inserted": 2,
    "updated": 0,
    "skipped": 0,
    "failed": 0
  },
  "details": [
    {
      "index": 0,
      "record": {
        "email": "user1@example.com",
        "email_verified": true,
        "password": {
          "password_hash": "REDACTED",
          "type": "bcrypt"
        }
      },
      "outcome": "inserted",
      "user_id": "0f0f65ee-4c7d-45a0-a740-bcbbfd3fcf06"
    },
    {
      "index": 1,
      "record": {
        "email": "user2@example.com",
        "email_verified": false,
        "family_name": "Doe",
        "given_name": "John",
        "name": "John Doe",
        "password": {
          "password_hash": "REDACTED",
          "type": "bcrypt"
        }
      },
      "outcome": "inserted",
      "user_id": "9c71fc29-6db6-4a18-aa73-774139fed16d",
      "warnings": [
        {
          "message": "email_verified = false has no effect in insert."
        }
      ]
    }
  ]
}
{
  "error": "Invalid request"
}

更新行为

属性的更新行为决定了当已有用户与指定 identifier 类型的值相同时,Authany 会如何处理该属性。例如,如果 identifier 为 "email",那么当已有用户的邮箱地址与您正在尝试导入的当前用户相同时,每个属性的更新行为就决定了 Authany 会如何处理该属性。

每个属性都可以具有以下三种更新行为之一:

  • UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL:具有此更新行为的属性,如果新值不为 null,会将用户的该属性更新为新值。如果新值显式为 null,该属性会被从用户身上删除。如果该属性缺失,则不执行任何操作。
  • UPDATED_IF_PRESENT:当属性的更新行为为此项时,若该属性存在则会被更新。如果属性不存在,则不执行任何操作。
  • IGNORED:如果用户已存在,该属性的新值会被忽略。如果属性缺失,也不执行任何操作。

各字段的更新行为

下表列出了所有属性及其更新行为,供参考:

项目 更新行为 说明
preferred_username、email、phone_number UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL 如果它不是 identifier,则应用该更新行为。相应的登录 ID 会按需被创建、更新或删除。
email_verified、phone_number_verified UPDATED_IF_PRESENT 例如,在首次导入时,如果 email_verified 缺失,则邮箱会被标记为未验证。
所有其他标准属性 UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL 需要特别说明的是,address 不会与现有值合并,而是替换现有的 address 值。
custom_attributes.* UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL custom_attributes 中的每个属性,其更新行为分别独立应用。因此在 upsert 中缺失的自定义属性不会改变现有值。
roles、groups UPDATED_IF_PRESENT 如果存在,用户的角色和用户组会与该值保持一致。例如,假设用户原本拥有 ["role_a", "role_b"],而 roles 为 ["role_a", "role_c"],则 role_b 会被移除,role_c 会被添加。
disabled UPDATED_IF_PRESENT 重新导入记录时若未指定 disabled,不会意外更改此前通过其他方式设置的禁用状态。
password IGNORED 如果在记录首次导入时未提供该字段,后续导入无法再补充添加。
mfa.email UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL 如果提供,用户可以使用邮箱 OTP 进行双重验证。
mfa.phone_number UPDATED_IF_PRESENT_AND_REMOVED_IF_NULL 如果提供,用户可以使用手机 OTP 进行双重验证。
mfa.password IGNORED 如果在记录首次导入时未提供该字段,后续导入无法再补充添加。
mfa.totp IGNORED 如果在记录首次导入时未提供该字段,后续导入无法再补充添加。

使用示例

以下是一份详细指南,包含使用用户导入 API 批量导入用户以及查询任务状态的示例。

使用用户导入 API 导入用户