ข้ามไปยังเนื้อหาหลัก

การค้นหาผู้ใช้ขั้นสูง

ใช้ Management API โดยตรงเพื่อใช้เงื่อนไขการค้นหาผู้ใช้ขั้นสูง

ดำเนินการค้นหา​

ใช้ GET /api/users สำหรับการค้นหาผู้ใช้ โปรดทราบว่านี่คือ Management API ที่ต้องการการยืนยันตัวตนเช่นเดียวกับ API อื่น ๆ ดู การโต้ตอบกับ Management API สำหรับตัวอย่างการใช้งาน

ตัวอย่าง​

Request

curl \
--location \
--request GET \
'http://<your-logto-endpoint>/api/users?search=%25alice%25'

Response

อาร์เรย์ของเอนทิตี User

[
{
"id": "MgUzzDsyX0iB",
"username": "alice_123",
"primaryEmail": "alice@some.email.domain",
"primaryPhone": null,
"name": null,
"avatar": null
// ...
}
]

พารามิเตอร์​

คำขอค้นหาประกอบด้วยคีย์พารามิเตอร์ดังต่อไปนี้:

  • คำค้นหา: search, search.*
  • โหมดการค้นหาสำหรับแต่ละฟิลด์: mode, mode.* (ค่าเริ่มต้น 'like', ตัวเลือกที่ใช้ได้ ['exact', 'like', 'similar_to', 'posix'])
  • โหมดการเชื่อมโยง: joint หรือ jointMode (ค่าเริ่มต้น 'or', ตัวเลือกที่ใช้ได้ ['or', 'and'])
  • การแยกแยะตัวพิมพ์เล็ก/ใหญ่: isCaseSensitive (ค่าเริ่มต้น false)

API นี้รองรับ การแบ่งหน้า (pagination)

มาดูตัวอย่างการใช้งานแต่ละพารามิเตอร์กัน โดยพารามิเตอร์การค้นหาทั้งหมดจะถูกจัดรูปแบบเป็น constructor ของ URLSearchParams

คำเตือน:

โหมดการค้นหาตั้งเป็น like โดยค่าเริ่มต้น ซึ่งใช้ Approximate string matching (“fuzzy search” หรือการค้นหาแบบคลุมเครือ)

บันทึก:

โหมดการค้นหาแบบ fuzzy ทั้งหมดรองรับการจับคู่ค่าต่อฟิลด์เพียงค่าเดียว หากต้องการจับคู่หลายค่าต่อฟิลด์เดียว ควรใช้โหมด “exact” ดู การจับคู่แบบ exact และการแยกแยะตัวพิมพ์เล็ก/ใหญ่ สำหรับรายละเอียด

หากต้องการค้นหาแบบ fuzzy ในทุกฟิลด์ที่มี เพียงระบุค่าให้กับคีย์ search จะใช้ ตัวดำเนินการ like เบื้องหลัง:

new URLSearchParams([['search', '%foo%']]);

การค้นหานี้จะวนในทุกฟิลด์ที่รองรับ เช่น id, primaryEmail, primaryPhone, username, name

ระบุฟิลด์ที่ต้องการค้นหา​

หากต้องการจำกัดการค้นหาเฉพาะใน name เท่านั้น เช่น ต้องการค้นหาผู้ใช้ที่มี foo อยู่ในชื่อ ให้ใช้สัญลักษณ์ . เพื่อระบุฟิลด์:

new URLSearchParams([['search.name', '%foo%']]);

โปรดจำไว้ว่าฟิลด์ซ้อนกัน (nested fields) ไม่รองรับ เช่น search.name.first จะเกิดข้อผิดพลาด

คุณสามารถระบุหลายฟิลด์พร้อมกันได้เช่นกัน:

new URLSearchParams([
['search.name', '%foo%'],
['search.primaryEmail', '%@gmail.com'],
]);

หมายถึงค้นหาผู้ใช้ที่มี foo ในชื่อ หรือ อีเมลลงท้ายด้วย @gmail.com

เปลี่ยนโหมดการเชื่อมโยง (joint mode)​

หากต้องการให้ API คืนค่าผลลัพธ์ที่ตรงกับทุกเงื่อนไข ให้ตั้งค่า joint mode เป็น and:

new URLSearchParams([
['search.name', '%foo%'],
['search.primaryEmail', '%@gmail.com'],
['joint', 'and'],
]);

หมายถึงค้นหาผู้ใช้ที่มี foo ในชื่อ และ อีเมลลงท้ายด้วย @gmail.com

การจับคู่แบบ exact และการแยกแยะตัวพิมพ์เล็ก/ใหญ่​

สมมติว่าต้องการค้นหาผู้ใช้ที่ชื่อ “Alice” แบบตรงตัว สามารถตั้งค่า mode.name เป็น exact ได้

new URLSearchParams([
['search.name', 'Alice'],
['mode.name', 'exact'],
]);

คุณอาจพบว่าผลลัพธ์เหมือนกับการใช้โหมด like (ค่าเริ่มต้น) เทียบกับ exact ความแตกต่างคือโหมด exact ใช้ = ในการเปรียบเทียบ ขณะที่ like ใช้ like หรือ ilike โดยทฤษฎีแล้ว = จะมีประสิทธิภาพดีกว่า

นอกจากนี้ ในโหมด exact คุณสามารถส่งหลายค่าเพื่อจับคู่ และค่าต่าง ๆ จะถูกเชื่อมด้วย or:

new URLSearchParams([
['search.name', 'Alice'],
['search.name', 'Bob'],
['mode.name', 'exact'],
]);

จะจับคู่ผู้ใช้ที่ชื่อ “Alice” หรือ “Bob”

โดยค่าเริ่มต้น การค้นหาไม่แยกแยะตัวพิมพ์เล็ก/ใหญ่ หากต้องการให้แยกแยะ ให้ตั้งค่า isCaseSensitive เป็น true:

new URLSearchParams([
['search.name', 'Alice'],
['search.name', 'Bob'],
['mode.name', 'exact'],
['isCaseSensitive', 'true'],
]);

โปรดทราบว่า isCaseSensitive เป็นการตั้งค่าระดับ global ทุกฟิลด์จะถูกบังคับใช้

การใช้ Regular expression (RegEx)​

PostgreSQL รองรับ regular expression สองแบบ คือ similar to และ posix ตั้งค่า mode เป็น similar_to หรือ posix เพื่อค้นหาด้วย regular expression:

new URLSearchParams([
['search', '^T.?m Scot+$'],
['mode', 'posix'],
]);

หมายเหตุ โหมด similar_to ใช้ได้เฉพาะการค้นหาแบบแยกแยะตัวพิมพ์เล็ก/ใหญ่เท่านั้น

การ override โหมดการจับคู่​

โดยปกติ คำค้นหาทั้งหมดจะสืบทอดโหมดการจับคู่จากการค้นหาหลัก:

new URLSearchParams([
['search', '^T.?m Scot+$'],
['mode', 'posix'],
['search.primaryEmail', 'tom%'], // โหมด posix
['joint', 'and'],
]);

หากต้องการ override เฉพาะฟิลด์:

new URLSearchParams([
['search', '^T.?m Scot+$'],
['mode', 'posix'],
['search.primaryEmail', 'tom%'], // โหมด like
['mode.primaryEmail', 'like'],
['search.phone', '0{3,}'], // โหมด posix
['joint', 'and'],
]);

ค้นหาด้วย external identity​

หากต้องการค้นหาผู้ใช้ที่เชื่อมโยงกับ social หรือ enterprise SSO identity ให้ส่ง query parameter สามตัวนี้พร้อมกันเพื่อค้นหาแบบ exact:

  • identityType: social สำหรับตัวตนแบบ social connector หรือ sso สำหรับ enterprise SSO identity
  • identityProvider: ตัวเชื่อมต่อสำหรับ social identity (เช่น dingtalk) หรือผู้ออก (issuer) สำหรับ enterprise SSO identity
  • identityId: ตัวระบุผู้ใช้ที่ออกโดยผู้ให้บริการ external identity
// ค้นหาผู้ใช้ที่เชื่อมกับ DingTalk social identity
new URLSearchParams([
['identityType', 'social'],
['identityProvider', 'dingtalk'],
['identityId', 'dingtalk-open-id'],
]);
// ค้นหาผู้ใช้ที่เชื่อมกับ enterprise SSO identity
new URLSearchParams([
['identityType', 'sso'],
['identityProvider', 'https://example.com/issuer'],
['identityId', 'enterprise-user-id'],
]);

ตัวกรอง identity จะถูกเชื่อมกับตัวกรองการค้นหาอื่น ๆ ด้วยตรรกะ AND เช่น หากต้องการค้นหา identity พร้อมกับ keyword เพิ่มเติม:

new URLSearchParams([
['identityType', 'social'],
['identityProvider', 'dingtalk'],
['identityId', 'dingtalk-open-id'],
['search', '%foo%'],
]);

ค้นหาด้วย custom data​

หากต้องการค้นหาผู้ใช้ด้วยค่าที่เก็บใน custom data ให้ส่งพารามิเตอร์ customData หนึ่งค่าหรือมากกว่านั้นใน GET /api/users แต่ละค่าต้องเป็น JSON object ที่ถูก URL-encode:

curl \
--get \
--data-urlencode 'customData={"qq":114514}' \
'http://<your-logto-endpoint>/api/users'

--data-urlencode จะ encode JSON object ให้คุณ URL ที่ได้เทียบเท่ากับ GET /api/users?customData=%7B%22qq%22%3A114514%7D

บันทึก:

การค้นหาด้วย custom data อาจช้าหาก tenant มีผู้ใช้จำนวนมาก ควรใช้ customData ร่วมกับตัวกรองอื่น เช่น search หรือ identity lookup เพื่อจำกัดขอบเขตการค้นหา

Logto จะจับค่ากับ custom_data ของผู้ใช้โดยใช้ JSONB containment โดยต้องตรงเฉพาะคีย์ที่ระบุใน value เท่านั้น คีย์อื่นใน custom data ของผู้ใช้จะถูกละเว้น

  • ประเภทข้อมูลต้องตรงกัน: ตัวเลข 114514 ไม่ตรงกับสตริง "114514"
  • สตริงแยกแยะตัวพิมพ์เล็ก/ใหญ่
  • null จะตรงกับ JSON null เท่านั้น ไม่ตรงกับคีย์ที่ไม่มี
  • อ็อบเจกต์ซ้อนจะจับคู่แบบ recursive
  • อาร์เรย์จะจับคู่ตาม element โดยไม่สนลำดับหรือค่าซ้ำ

ทุกคีย์ใน JSON object เดียวกันต้องตรงกัน (AND) หากส่ง customData หลายครั้ง ผู้ใช้จะตรงเมื่อ object ใด object หนึ่งตรง (OR):

curl \
--get \
--data-urlencode 'customData={"qq":114514}' \
--data-urlencode 'customData={"wechat":"logto"}' \
'http://<your-logto-endpoint>/api/users'

ตัวกรอง custom data จะถูกเชื่อมกับตัวกรองอื่น ๆ เสมอด้วย AND รวมถึง search, identity lookup (identityType, identityProvider, และ identityId), excludeRoleId, และ excludeOrganizationId เช่น ตัวอย่างนี้จะคืนค่าผู้ใช้ที่ qq เป็น 114514 และ username มี alice:

curl \
--get \
--data-urlencode 'customData={"qq":114514}' \
--data-urlencode 'search.username=%alice%' \
'http://<your-logto-endpoint>/api/users'

พารามิเตอร์ mode, joint, และ isCaseSensitive มีผลเฉพาะกับการค้นหาด้วย keyword เท่านั้น ไม่มีผลกับ customData

API จะคืนค่า 400 Bad Request เมื่อค่าของ customData ไม่ใช่ JSON object ที่ถูกต้อง (เช่น [] หรือ 114514), เป็น object ว่าง {} หรือมี object หรือ array ว่างในทุกระดับ (เช่น {"profile":{}} หรือ {"tags":[]}) ชื่อพารามิเตอร์แบบ nested เช่น customData.qq, customData[qq], และ mode.customData ก็จะถูกปฏิเสธด้วย 400 เช่นกัน