跳到主要内容

用户迁移

Logto 支持从其他身份系统批量或即时迁移现有用户。本指南将介绍如何通过 Management API 批量导入用户,以及迁移前需要注意的事项。

选择迁移策略​

策略适用场景工作原理
批量迁移你可以以 Logto 支持的格式导出用户记录和密码哈希。在切换前通过 Management API 导入用户,按照本指南的其余部分操作。
即时迁移你需要针对现有系统验证密码,无法导出兼容的密码哈希,或希望逐步迁移活跃用户。配置 首次因子验证后 Action。在用户首次密码登录时,Logto 通过你的 Action 验证凭据,创建或更新用户,并存储新的本地密码哈希。

即时迁移会在用户迁移完成前,将遗留认证 (Authentication) 服务保留在登录请求路径中。请使用快速、可靠的 HTTPS 端点,并在迁移期间保持其可用。

用户数据结构​

在开始之前,让我们先了解一下 Logto 的 用户数据结构。用户数据结构有三部分需要注意:

  1. 基础数据:来自用户资料的基本信息,你可以将现有用户资料中的数据映射到这里。
  2. 自定义数据:用于存储额外的用户信息,可以用来存放无法映射到基础数据的内容。
  3. 社交身份:存储通过社交登录获取的用户信息。

你可以创建一个映射,将现有用户资料中的信息对应到 基础数据 和 自定义数据。对于社交登录,你需要额外的步骤来导入社交身份,请参考 关联社交身份到用户 的 API。

保留现有用户 ID​

默认情况下,Logto 会为通过 Management API 创建的每个用户生成一个随机 ID。如果你的应用已经存储了来自之前身份提供商的用户 ID,可以在 创建用户 请求体中传递可选的 id 字段来保留它们。这样可以避免维护新旧 ID 的映射表。

ID 必须为 1 到 128 个字符,可包含字母、数字和 _ - . @ : + = |。这涵盖了常见格式,如 auth0|5f7c8ec7c33c6c004bbafe82、google-oauth2|103547991597142817347、UUID、user_01H8MZ2QK3V4X5Y6Z7 和邮箱地址。不允许 URL 路径中无效的字符(空格、/、?、#、%、\),否则会返回 400,因为 ID 会用于 /api/users/{userId}。如果 ID 已被占用,请求会以 422 user.id_already_in_use 失败。

{
"id": "auth0|5f7c8ec7c33c6c004bbafe82",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Bcrypt",
"passwordDigest": "$2b$10$..."
}
备注:

自定义用户 ID 仅支持自托管 Logto。Logto Cloud 会拒绝包含 id 的请求,并返回 501 request.feature_not_supported,因为用户 ID 在租户间是共享的。

密码哈希​

Logto 使用 Argon2 对用户密码进行哈希,同时也支持 MD5、SHA1、SHA256 和 Bcrypt 等其他算法,方便迁移。这些算法被认为不安全,相应的密码哈希会在用户首次成功登录后迁移为 Argon2。

如果你使用了其他哈希算法或加盐方式,可以将 passwordAlgorithm 设置为 Legacy,这样你可以使用 Node.js 支持的任意哈希算法。支持的算法列表可在 Node.js crypto 文档 中找到。在这种情况下,passwordDigest 应为包含哈希算法及其他算法参数的 JSON 字符串。

通用 Legacy 格式​

JSON 字符串的格式如下:

["hash_algorithm", ["argument1", "argument2", ...], "expected_hashed_value"]

你可以用 @ 作为参数中的实际密码占位符。

例如,如果你使用 SHA256 加盐,可以按如下格式存储密码:

["sha256", ["salt123", "@"], "c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e"]

等价于如下代码:

const hash = crypto.createHash('sha256');
hash.update('salt123' + 'password123');
// 期望的哈希值
const expectedHashedValue = hash.digest('hex');

PBKDF2 支持​

Logto 特别支持 PBKDF2。

要迁移使用 PBKDF2 哈希的密码,将 passwordAlgorithm 设置为 Legacy,并将 passwordDigest 格式化如下:

["pbkdf2", ["salt", "1000", "20", "sha512", "@"], "expected_hashed_value"]

参数说明:

  • salt:原始哈希中使用的盐值
  • iterations:迭代次数(如 "1000")
  • keylen:派生密钥的字节长度(如 "20")
  • digest:所用哈希函数(如 "sha512"、"sha256"、"sha1")
  • @:实际密码值的占位符
  • expected_hashed_value:期望的哈希结果(十六进制字符串)

迁移示例请求体:

{
"username": "john_doe",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Legacy",
"passwordDigest": "[\"pbkdf2\", [\"mySalt123\", \"1000\", \"20\", \"sha512\", \"@\"], \"c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e\"]"
}

迁移步骤​

  1. 准备用户数据
    你应先从现有平台导出用户数据,然后将用户信息映射到 Logto 用户数据结构。建议将映射后的数据整理为 JSON 格式。以下是用户数据示例:

    [
    {
    "username": "user1",
    "passwordDigest": "password-encrypted",
    "passwordAlgorithm": "SHA256"
    },
    {
    "username": "user2",
    "passwordDigest": "password-encrypted",
    "passwordAlgorithm": "SHA256"
    }
    ]
  2. 创建 Logto 租户
    你需要在 Logto 中设置一个租户。可以选择 Logto Cloud 或 Logto OSS。如果还未完成,请参考 设置 Logto cloud 指南。

  3. 配置 Management API 连接
    我们将使用 Management API 导入用户数据,你可以参考 Management API 了解如何在开发环境中配置连接。

  4. 导入用户数据
    建议编写脚本逐个导入用户数据,我们将调用 创建用户 API。以下是脚本示例:

    const users = require('./users.json');

    const importUsers = async () => {
    for (const user of users) {
    try {
    await fetch('https://[tenant_id].logto.app/api/users', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer [your-access-token]',
    },
    body: JSON.stringify(user),
    });
    // 为避免速率限制,暂停一会
    await new Promise((resolve) => setTimeout(resolve, 200));
    } catch (error) {
    console.error(`Failed to import user ${user.username}: ${error.message}`);
    }
    }
    };

    importUsers();

请注意,API 接口有速率限制,你应在每次请求之间添加延时以避免触发速率限制。详情请查阅我们的 速率限制 页面。

如果你有大量用户数据(10 万以上),可以 联系我们 以提升速率限制。

将现有用户数据库迁移到 Logto 的通用指南