การย้ายผู้ใช้ (User migration)
Logto รองรับทั้งการย้ายผู้ใช้แบบกลุ่ม (bulk) และแบบ Just-in-time จากระบบข้อมูลระบุตัวตนเดิม คู่มือนี้อธิบายวิธีนำเข้าผู้ใช้แบบกลุ่มผ่าน Management API และสิ่งที่ควรพิจารณาก่อนการย้าย
เลือกกลยุทธ์การย้าย
| กลยุทธ์ | เลือกใช้เมื่อ | วิธีการทำงาน |
|---|---|---|
| การย้ายแบบกลุ่ม | คุณสามารถส่งออกข้อมูลผู้ใช้และรหัสผ่านที่เข้ารหัสในรูปแบบที่ Logto รองรับได้ | นำเข้าผู้ใช้ก่อนการเปลี่ยนผ่านผ่าน Management API ตามขั้นตอนในคู่มือนี้ |
| การย้ายแบบ Just-in-time | คุณต้องตรวจสอบรหัสผ่านกับระบบเดิม ไม่สามารถส่งออกรหัสผ่านที่เข้ารหัสในรูปแบบที่รองรับ หรืออยากย้ายผู้ใช้ที่ใช้งานอยู่ทีละน้อย | กำหนดค่า Post first-factor verification Action เมื่อผู้ใช้ลงชื่อเข้าใช้ด้วยรหัสผ่านครั้งแรก Logto จะตรวจสอบข้อมูลรับรองผ่าน Action ของคุณ สร้างหรืออัปเดตผู้ใช้ และจัดเก็บรหัสผ่านใหม่ในรูปแบบ local hash |
การย้ายแบบ Just-in-time จะคงบริการการยืนยันตัวตนเดิมไว้ในเส้นทางคำขอลงชื่อเข้าใช้จนกว่าผู้ใช้จะถูกย้าย ควรใช้ endpoint HTTPS ที่รวดเร็วและเชื่อถือได้ และเปิดใช้งานตลอดช่วงเวลาการย้าย
สคีมาผู้ใช้
ก่อนเริ่มต้น มาดู user schema ใน Logto กันก่อน สคีมาผู้ใช้มี 3 ส่วนที่ควรทราบ:
- ข้อมูลพื้นฐาน: คือข้อมูลพื้นฐานจากโปรไฟล์ผู้ใช้ คุณสามารถจับคู่ข้อมูลจากโปรไฟล์ผู้ใช้เดิมของคุณได้
- ข้อมูลกำหนดเอง: เก็บข้อมูลผู้ใช้เพิ่มเติม ใช้สำหรับเก็บไฟล์หรือข้อมูลที่ไม่สามารถจับคู่กับข้อมูลพื้นฐานได้
- ข้อมูลโซเชียล: เก็บข้อมูลผู้ใช้ที่ได้จากการลงชื่อเข้าใช้ด้วยโซเชียล
คุณสามารถสร้างแผนที่จับคู่ข้อมูลผู้ใช้จากโปรไฟล์เดิมไปยัง ข้อมูลพื้นฐาน และ ข้อมูลกำหนดเอง สำหรับการลงชื่อเข้าใช้ด้วยโซเชียล จะต้องมีขั้นตอนเพิ่มเติมในการนำเข้าข้อมูลโซเชียล โปรดดู API ของ Link social identity to user
เก็บ ID ผู้ใช้เดิม
โดยปกติ Logto จะสร้าง ID แบบสุ่มให้ผู้ใช้ทุกคนที่สร้างผ่าน Management API หากแอปของคุณมีการเก็บ ID ผู้ใช้จากผู้ให้บริการข้อมูลระบุตัวตนเดิมอยู่แล้ว คุณสามารถเก็บ ID เดิมได้โดยส่ง id (ไม่บังคับ) ใน request body ของ create user วิธีนี้ช่วยหลีกเลี่ยงการต้องสร้างตาราง mapping ระหว่าง ID เก่าและใหม่
ID ต้องมีความยาว 1 ถึง 128 ตัวอักษร และสามารถประกอบด้วยตัวอักษร ตัวเลข และ _ - . @ : + = | ครอบคลุมรูปแบบทั่วไป เช่น auth0|5f7c8ec7c33c6c004bbafe82, google-oauth2|103547991597142817347, UUIDs, user_01H8MZ2QK3V4X5Y6Z7 และอีเมล ตัวอักษรที่ไม่ถูกต้องใน URL path (ช่องว่าง, /, ?, #, %, \) จะถูกปฏิเสธด้วย 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$..."
}
Custom user IDs รองรับเฉพาะใน Logto ที่ติดตั้งเอง (self-hosted) เท่านั้น Logto Cloud จะปฏิเสธคำขอที่มี id ด้วย 501 request.feature_not_supported เพราะ ID ผู้ใช้ถูกแชร์ข้าม tenant
การแฮชรหัสผ่าน
Logto ใช้ Argon2 ในการแฮชรหัสผ่านผู้ใช้ และยังรองรับอัลกอริทึมอื่น เช่น MD5, SHA1, SHA256 และ Bcrypt เพื่อความสะดวกในการย้าย อัลกอริทึมเหล่านี้ถือว่าไม่ปลอดภัย รหัสผ่านที่แฮชด้วยอัลกอริทึมเหล่านี้จะถูกย้ายไป Argon2 เมื่อผู้ใช้ลงชื่อเข้าใช้สำเร็จครั้งแรก
หากคุณใช้อัลกอริทึมหรือ salt อื่น สามารถตั้งค่า passwordAlgorithm เป็น Legacy เพื่อใช้แฮชอัลกอริทึมใดก็ได้ที่ Node.js รองรับ ดูรายการอัลกอริทึมที่รองรับได้ใน Node.js crypto documentation ในกรณีนี้ passwordDigest จะเป็น JSON string ที่มีชื่ออัลกอริทึมและพารามิเตอร์เฉพาะ
รูปแบบ Legacy ทั่วไป
รูปแบบของ JSON string คือ:
["hash_algorithm", ["argument1", "argument2", ...], "expected_hashed_value"]
และสามารถใช้ @ เป็นตัวแทนรหัสผ่านจริงใน argument ได้
ตัวอย่าง หากใช้ SHA256 กับ salt สามารถเก็บรหัสผ่านในรูปแบบนี้:
["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: ค่า salt ที่ใช้ในการแฮชเดิมiterations: จำนวนรอบ (เช่น"1000")keylen: ความยาวของคีย์ที่ได้ (เช่น"20")digest: ฟังก์ชันแฮชที่ใช้ (เช่น"sha512","sha256","sha1")@: ตัวแทนรหัสผ่านจริงexpected_hashed_value: ผลลัพธ์ hash ที่คาดหวังในรูปแบบ hexadecimal
ตัวอย่าง payload สำหรับการย้าย:
{
"username": "john_doe",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Legacy",
"passwordDigest": "[\"pbkdf2\", [\"mySalt123\", \"1000\", \"20\", \"sha512\", \"@\"], \"c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e\"]"
}
รองรับ Firebase scrypt
Logto ยังรองรับ อัลกอริทึม scrypt ที่ปรับแต่งโดย Firebase ตั้งค่า passwordAlgorithm เป็น Legacy และจัดรูปแบบ passwordDigest ดังนี้:
[
"firebase-scrypt",
["salt", "signer_key", "salt_separator", "rounds", "mem_cost", "@"],
"expected_hashed_value"
]
พารามิเตอร์คือ:
salt:saltของผู้ใช้จากfirebase auth:exportsigner_key,salt_separator,rounds,mem_cost: พารามิเตอร์การแฮชรหัสผ่านของโปรเจกต์คุณ ดูได้ใน Firebase console ที่ Authentication > Users > ⋮ > Password hash parameters@: ตัวแทนรหัสผ่านจริงexpected_hashed_value:passwordHashของผู้ใช้จากการ export ในรูปแบบ base64 มาตรฐาน หากอ่านผู้ใช้ด้วย Firebase Admin SDK ให้แปลง base64 แบบ URL-safe (-,_) เป็น base64 มาตรฐาน (+,/) ก่อน
passwordDigest จำกัดที่ 256 ตัวอักษร ควร serialize เป็น JSON แบบ compact ไม่มีช่องว่าง (เช่น ใช้ JSON.stringify)
ผู้ใช้ที่นำเข้าใน Firebase ด้วย hash ที่ไม่ใช่ scrypt และยังไม่เคยลงชื่อเข้าใช้ จะถูก export โดยไม่มี passwordHash และ salt ให้นำเข้าด้วย hash เดิมถ้ายังมี หรือให้ผู้ใช้รีเซ็ตรหัสผ่าน
ตัวอย่าง payload สำหรับการย้าย:
{
"username": "john_doe",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Legacy",
"passwordDigest": "[\"firebase-scrypt\",[\"42xEC+ixf3L2lw==\",\"jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==\",\"Bw==\",\"8\",\"14\",\"@\"],\"lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==\"]"
}
ขั้นตอนการย้าย
-
เตรียมข้อมูลผู้ใช้ ควรส่งออกข้อมูลผู้ใช้จากแพลตฟอร์มเดิม แล้วแมปข้อมูลผู้ใช้ไปยังสคีมาผู้ใช้ของ Logto แนะนำให้เตรียมข้อมูลที่แมปแล้วในรูปแบบ JSON ตัวอย่างข้อมูลผู้ใช้:
[{"username": "user1","passwordDigest": "password-encrypted","passwordAlgorithm": "SHA256"},{"username": "user2","passwordDigest": "password-encrypted","passwordAlgorithm": "SHA256"}] -
สร้าง tenant ใน Logto คุณต้องตั้งค่า tenant ใน Logto สามารถใช้ Logto Cloud หรือ Logto OSS ก็ได้ หากยังไม่ได้ตั้งค่า โปรดดูคู่มือ Set up Logto cloud
-
ตั้งค่าการเชื่อมต่อ Management API เราจะใช้ Management API ในการนำเข้าข้อมูลผู้ใช้ ดูวิธีตั้งค่าการเชื่อมต่อในสภาพแวดล้อมพัฒนาของคุณได้ที่ Management API
-
นำเข้าข้อมูลผู้ใช้ แนะนำให้เตรียมสคริปต์เพื่อนำเข้าข้อมูลผู้ใช้ทีละคน โดยเรียก API create user ตัวอย่างสคริปต์:
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),});// หน่วงเวลาเล็กน้อยเพื่อหลีกเลี่ยง rate limitawait new Promise((resolve) => setTimeout(resolve, 200));} catch (error) {console.error(`นำเข้าผู้ใช้ ${user.username} ไม่สำเร็จ: ${error.message}`);}}};importUsers();
โปรดทราบว่า endpoint ของ API มีการจำกัดอัตรา (rate limit) ควรเพิ่มการหน่วงเวลาระหว่างแต่ละคำขอเพื่อหลีกเลี่ยง rate limit โปรดดูรายละเอียดที่หน้า rate limits
หากคุณมีข้อมูลผู้ใช้จำนวนมาก (100,000+ คน) สามารถ ติดต่อเรา เพื่อขอเพิ่ม rate limit ได้
แหล่งข้อมูลที่เกี่ยวข้อง
แนวทางทั่วไปสำหรับการย้ายฐานข้อมูลผู้ใช้เดิมของคุณไปยัง Logto