繁體中文(台灣)
  • migration
  • user-migration
  • migration-challenges
  • workaround

將現有用戶資料庫遷移至 Logto 的一般指南

本文介紹如何利用現有工具將先前的用戶數據遷移到 Logto,在 Logto 尚未提供數據遷移服務的情況下。

Darcy Ye
Darcy Ye
Developer

Logto 目前還沒有一系列的數據遷移工具,但我們已公開了管理 API 的基本功能。這不會妨礙用戶通過編寫腳本來完成現有用戶資料庫的遷移。

考慮到從社群用戶收到的一些需求,以及我們目前沒有文檔來解釋用戶資料庫遷移的具體步驟,我們在本文中做了一個恰當的介紹,以幫助用戶找到具體的想法,並節省閱讀 Logto 代碼和文檔的時間。

步驟 1:了解 Logto 的基本用戶數據結構和使用案例

Logto 使用 PostgreSQL 資料庫。除了其各種性能優勢外,一個重要原因是它支持自定義 JSON/JSONB 數據類型,並允許在 JSON 類型數據的內部值上構建索引,平衡數據庫的性能和可擴展性。

有關 Logto 的用戶數據結構,請參考 用戶參考 以了解所有細節。在此我們著重描述 Logto 可能與其他身份服務不同的一些方面。

id

這是為 Logto 用戶隨機生成的內部唯一識別碼。用戶在使用基於 Logto 的服務時不會注意到 id

熟悉數據庫的工程師應該不會覺得奇怪。即使是最基本的身份系統也會有一個 id 來唯一識別用戶,儘管它們的形式通常不同。一些身份服務可能使用用戶名來唯一識別用戶。

username, primaryEmail, primaryPhone

在這裡,用戶名、主電子郵件、主電話是 Logto 與其他身份系統大不相同的地方 —— 它們都可以作為終端用戶感知的唯一標識符。

在許多其他身份系統中,使用用戶名進行識別(帳戶之間的用戶名不能重複),這很容易理解。

但在 Logto 中,主電子郵件/電話也用來區分用戶。也就是說,如果用戶 A 已經有主電子郵件 [email protected],那麼其他用戶 B 不能將此電子郵件地址添加為其主電子郵件。主電話的工作原理類似。

一些其他身份系統允許使用不同的用戶名註冊多個帳戶但綁定相同的電子郵件/電話,這在 Logto 中是不允許的(電子郵件/電話可以添加到 Logto 的 customData 中)。這是因為在 Logto 中主電子郵件/電話可以用於無密碼登入。

identities

Logto 定義這個 identities 字段為 JSON 類型,其類型定義如下:

近年來,為了方便獲取新用戶,身份系統允許用戶通過一些擁有大量用戶的現有社交賬戶快速登入,例如 google / facebook 等。

在下面的例子中,identities 字段存儲社交登入信息:

其中 facebookgithub 是社交服務提供者的名稱,userId 是用戶用於登入的社交賬戶的 iddetails 還包括一些用戶授權社交提供者顯示的其他信息,這些信息會在特定時間添加到用戶的 Logto 用戶資料中。

如果先前的數據庫包含用戶所使用的社交提供者的名稱(例如 facebookgoogle)和 id(見上例中的 userId),那麼 Logto 用戶可以直接用相同的社交賬戶登入。

customData

此字段可以存儲任何與用戶相關的信息,例如上面提到的無法用於無密碼登入的電子郵件/電話(可以用於接收通知或其他業務相關功能)等。

其他字段相對容易理解(除了 passwordEncryptedpasswordEncryptionMethod,這將於後面解釋),請自行閱讀文檔。

步驟 2:撰寫資料庫遷移腳本

對於大規模的數據庫遷移,編寫遷移腳本是最常見的方法。我們將提供一個簡單的例子來幫助理解如何撰寫遷移腳本,以滿足不同的需求。

需要注意的是,撰寫遷移腳本時,我們跳過了檢索原始數據的過程,因為獲取數據的方法有很多,比如從數據庫導出到文件然後讀取文件,或者通過 API 來獲取。 這些不是遷移腳本的重點,所以我們在這裡不詳述。

當你在遷移腳本中看到 tenant_id 時,你可能會感到奇怪。Logto 是基於多租戶架構的。對於開源 Logto (Logto OSS) 用戶,你可以將用戶的 tenant_id 設置為 default

對於自主託管的 Logto OSS 用戶來說,數據庫連接易於獲取。然而,對於 Logto 雲端用戶來說,出於安全原因,我們目前無法向用戶提供數據庫連接許可權。用戶需要參考 API 文檔 並使用與用戶相關的 API 進行用戶遷移。我們理解這種方法不適合大規模的用戶數據遷移,但目前仍可以處理有限數量的用戶遷移。

步驟 3:散列密碼遷移挑戰及潛在解決方案

在我們之前的 博客 中,我們談到了一些防止密碼攻擊的措施。一個身份基礎設施提供者可以做的是不存儲明文密碼而是儲存散列密碼。

另一篇 博客文章 解釋了密碼散列,其中說明了散列值是不可逆的。

第二篇博客文章還比較了一些散列算法的演進。Logto 本身使用文章中提到的 Argon2i 算法,暫不支持其他散列算法。這意味著使用其他散列算法的舊用戶數據庫的密碼散列無法直接遷移到 Logto 的數據庫。

即便 Logto 除了 Argon2i 外還支持其他常用的散列算法,也因為應用散列算法時鹽的靈活性而難以直接遷移舊數據。

除了在未來支持其他散列算法外,Logto 還很可能提供自定義鹽計算方法,以適應各種情況。

在此之前,你可以使用 Logto 的 登入體驗配置 允許用戶通過其他方式(如電子郵件 + 驗證碼)登入並在進入應用程序前填寫新密碼(將使用 Argon2i 散列算法進行加密)。然後新的密碼可以用於後續登入。

需要注意的是,如果原始用戶數據僅支持使用密碼登入,則上述解決方案將無法解決這種情況。因為前述解決方案其實是通過使用替代登入方式並利用 Logto 的終端用戶流程中的“必填信息補充”機制來解決密碼散列不兼容問題。

因此如果原始用戶數據中僅支持密碼登入,該解決方案無法解決這種情況,因為沒有可用的替代登入選項。

此處提到的解決方案並未真正解決散列密碼遷移問題,而是從 Logto 產品的角度提供了一個替代方案,以避免阻止用戶登入你的產品。

步驟 4:逐步切換到 Logto 並進行狀態監控

完成以上步驟後,終端用戶已經可以通過 Logto 登入並使用你的服務。

由於遷移期間通常不會中斷服務,可能會出現同步到 Logto 的用戶數據不是最新的情況。當檢測到這些不常見的案例時,則需要從舊數據庫同步到 Logto。

經過更長時間(或可能應用其他定義的度量標準)未發生數據不一致的情況後,就可以完全棄用舊數據庫。

結論

在這篇文章中,我們介紹了一個理想的數據庫遷移應經歷的步驟。

如果遇到上述未提及的問題,請不要猶豫加入我們的社群或聯繫我們尋求幫助。你遇到的問題也可能是他人遇到的問題,將成為我們未來設計遷移工具時需要考慮的議題。