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

เพิ่มการยืนยันตัวตนให้กับแอป Webflow ของคุณ (Add authentication to your Webflow application)

คู่มือนี้จะแสดงวิธีการผสาน Logto เข้ากับเว็บไซต์ Webflow ของคุณ

เคล็ดลับ:

โปรเจกต์ตัวอย่างสามารถดูได้ที่ Webflow project preview

ข้อกำหนดเบื้องต้น

  1. การผสาน Logto กับ Webflow จำเป็นต้องใช้ฟีเจอร์ "Custom code" ของ Webflow ซึ่งต้องมีอย่างน้อยแผน "Basic"
  2. เว็บไซต์ Webflow โดยสามารถใช้เว็บไซต์ที่มีอยู่แล้วหรือสร้างใหม่ก็ได้

การผสานระบบ

เริ่มต้น Logto provider

บันทึก:

ในขั้นตอนถัดไปนี้ เราจะสมมติว่าเว็บไซต์ Webflow ของคุณทำงานอยู่ที่ https://your-awesome-site.webflow.io

ในขั้นตอนนี้ เราจะเพิ่มโค้ดแบบกำหนดเองในระดับโกลบอลให้กับเว็บไซต์ Webflow ของคุณ เนื่องจาก Webflow ไม่รองรับ NPM เราจะใช้บริการ CDN ของ jsdelivr.com เพื่อนำเข้า Logto SDK

เปิดหน้า "Site settings" แล้วไปที่ส่วน "Custom code" จากนั้นเพิ่มโค้ดต่อไปนี้ในส่วน "Head code"

<script type="module">
// นำเข้า SDK `@logto/browser` จาก jsdelivr CDN
import LogtoClient from 'https://esm.run/@logto/browser';

// กำหนดอินสแตนซ์ `logtoClient` ให้กับ window object,
// เพื่อให้สามารถใช้งานแบบโกลบอลในหน้าอื่น ๆ ได้
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // เช่น http://localhost:3001
appId: '<your-application-id>',
});
</script>

ดำเนินการลงชื่อเข้าใช้

ก่อนที่เราจะลงลึกในรายละเอียด นี่คือภาพรวมประสบการณ์ของผู้ใช้ปลายทาง กระบวนการลงชื่อเข้าใช้สามารถสรุปได้ดังนี้:

  1. แอปของคุณเรียกใช้งานเมธอดลงชื่อเข้าใช้
  2. ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังหน้าลงชื่อเข้าใช้ของ Logto สำหรับแอปเนทีฟ ระบบจะเปิดเบราว์เซอร์ของระบบ
  3. ผู้ใช้ลงชื่อเข้าใช้และถูกเปลี่ยนเส้นทางกลับไปยังแอปของคุณ (ตามที่กำหนดไว้ใน redirect URI)

เกี่ยวกับการลงชื่อเข้าใช้แบบเปลี่ยนเส้นทาง (redirect-based sign-in)

  1. กระบวนการยืนยันตัวตนนี้เป็นไปตามโปรโตคอล OpenID Connect (OIDC) และ Logto บังคับใช้มาตรการรักษาความปลอดภัยอย่างเข้มงวดเพื่อปกป้องการลงชื่อเข้าใช้ของผู้ใช้
  2. หากคุณมีหลายแอป คุณสามารถใช้ผู้ให้บริการข้อมูลระบุตัวตน (Logto) เดียวกันได้ เมื่อผู้ใช้ลงชื่อเข้าใช้แอปหนึ่งแล้ว Logto จะดำเนินการลงชื่อเข้าใช้โดยอัตโนมัติเมื่อผู้ใช้เข้าถึงแอปอื่น

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับเหตุผลและประโยชน์ของการลงชื่อเข้าใช้แบบเปลี่ยนเส้นทาง โปรดดูที่ อธิบายประสบการณ์การลงชื่อเข้าใช้ของ Logto


กำหนดค่า URI สำหรับเปลี่ยนเส้นทางหลังลงชื่อเข้าใช้

ไปที่หน้ารายละเอียดแอปพลิเคชันของ Logto Console เพิ่ม Redirect URI https://your-awesome-site.webflow.io/callback แล้วคลิก "บันทึกการเปลี่ยนแปลง" (Save changes)

Redirect URI ใน Logto Console

สร้างปุ่มลงชื่อเข้าใช้

กลับไปที่ Webflow designer ของคุณ ลากและวางปุ่ม “Sign in” ลงในหน้าแรก และกำหนด ID เป็น “sign-in” เพื่อใช้อ้างอิงในภายหลังด้วย getElementById()

<script type="module">
const signInButton = document.getElementById('sign-in');
const onClickSignIn = () => logtoClient.signIn('https://your-awesome-site.webflow.io/callback');
signInButton.addEventListener('click', onClickSignIn);
</script>

จัดการการเปลี่ยนเส้นทาง

เกือบเสร็จแล้ว! ในขั้นตอนสุดท้ายนี้ เราใช้ https://your-awesome-site.webflow.io/callback เป็น Redirect URI และตอนนี้เราต้องจัดการกับมันอย่างถูกต้อง

ก่อนอื่น ให้สร้างหน้า "Callback" ใน Webflow แล้วใส่ข้อความคงที่ว่า "กำลังเปลี่ยนเส้นทาง..." (Redirecting...) ลงไป จากนั้นเพิ่มโค้ดกำหนดเองระดับหน้า (page-level custom code) ต่อไปนี้ลงในหน้า "Callback"

<script type="module">
(async () => {
// จัดการตรรกะ callback หลังลงชื่อเข้าใช้โดยเรียกเมธอดของ SDK
await logtoClient.handleSignInCallback(window.location.href);

// เปลี่ยนเส้นทางกลับไปยังหน้าแรกเมื่อจัดการเสร็จสิ้น
window.location.assign('https://your-awesome-site.webflow.io');
})();
</script>

ดำเนินการออกจากระบบ

การเรียกใช้ .signOut() จะล้างข้อมูล Logto ทั้งหมดในหน่วยความจำและ localStorage หากมีอยู่

หลังจากลงชื่อออกแล้ว จะเป็นการดีหากเปลี่ยนเส้นทางผู้ใช้กลับไปยังเว็บไซต์ของคุณ มาเพิ่ม https://your-awesome-site.webflow.io เป็นหนึ่งใน Post Sign-out URIs ใน Admin Console (แสดงอยู่ใต้ Redirect URIs) และใช้ URL นี้เป็นพารามิเตอร์เมื่อเรียก .signOut()

สร้างปุ่มลงชื่อออก

กลับไปที่ Webflow designer และเพิ่มปุ่ม “Sign out” ในหน้าแรกของคุณ เช่นเดียวกับก่อนหน้านี้ ให้กำหนด ID “sign-out” ให้กับปุ่ม และเพิ่มโค้ดต่อไปนี้ใน custom code ระดับหน้า

const signOutButton = document.getElementById('sign-out');
const onClickSignOut = () => logtoClient.signOut('https://your-awesome-site.webflow.io');
signOutButton.addEventListener('click', onClickSignOut);

จัดการสถานะการยืนยันตัวตน

ใน Logto SDK โดยทั่วไปเราสามารถใช้เมธอด logtoClient.isAuthenticated() เพื่อตรวจสอบสถานะการยืนยันตัวตน (authentication) ได้ หากผู้ใช้ลงชื่อเข้าใช้แล้ว ค่านี้จะเป็น true หากยังไม่ได้ลงชื่อเข้าใช้จะเป็น false

ในเว็บไซต์ Webflow ของคุณ คุณยังสามารถใช้วิธีนี้เพื่อแสดงหรือซ่อนปุ่มลงชื่อเข้าใช้และลงชื่อออกแบบโปรแกรมได้อีกด้วย ให้นำโค้ดต่อไปนี้ไปปรับใช้เพื่อเปลี่ยน CSS ของปุ่มตามสถานะ

const isAuthenticated = await logtoClient.isAuthenticated();

signInButton.style.display = isAuthenticated ? 'none' : 'block';
signOutButton.style.display = isAuthenticated ? 'block' : 'none';

จุดตรวจสอบ: ทดสอบเว็บไซต์ Webflow ของคุณ

ตอนนี้ ทดสอบเว็บไซต์ของคุณ:

  1. เผยแพร่และเข้าไปที่ URL ของเว็บไซต์คุณ ปุ่มลงชื่อเข้าใช้ควรจะแสดงให้เห็น
  2. คลิกปุ่มลงชื่อเข้าใช้ SDK จะเริ่มกระบวนการลงชื่อเข้าใช้ โดยเปลี่ยนเส้นทางคุณไปยังหน้าลงชื่อเข้าใช้ของ Logto
  3. หลังจากลงชื่อเข้าใช้แล้ว คุณจะถูกเปลี่ยนเส้นทางกลับมายังเว็บไซต์ของคุณ เห็นชื่อผู้ใช้และปุ่มลงชื่อออก
  4. คลิกปุ่มลงชื่อออกเพื่อออกจากระบบ

รับข้อมูลผู้ใช้

คุณสามารถใช้เมธอดของ Logto เหล่านี้เพื่อดึงข้อมูลผู้ใช้แบบโปรแกรมมิ่งได้:

  • getIdTokenClaims: รับข้อมูลผู้ใช้โดยการถอดรหัสโทเค็น ID (ID token) ในเครื่อง การอ้างสิทธิ์ (claims) บางรายการอาจไม่มีให้ใช้งาน
  • fetchUserInfo: รับข้อมูลผู้ใช้โดยการส่งคำขอไปยัง จุดปลาย userinfo (userinfo endpoint)

สิ่งสำคัญที่ควรทราบคือ การอ้างสิทธิ์ข้อมูลผู้ใช้ที่สามารถดึงมาได้ขึ้นอยู่กับขอบเขต (scopes) ที่ผู้ใช้เลือกขณะลงชื่อเข้าใช้ และเพื่อประสิทธิภาพและขนาดข้อมูล โทเค็น ID (ID token) อาจไม่มีการอ้างสิทธิ์ของผู้ใช้ทั้งหมด โดยการอ้างสิทธิ์บางรายการจะมีเฉพาะในจุดปลาย userinfo เท่านั้น (ดูรายการที่เกี่ยวข้องด้านล่าง)

Logto ใช้มาตรฐาน ขอบเขต (scopes) และ การอ้างสิทธิ์ (claims) ของ OIDC เพื่อกำหนดขอบเขตและการอ้างสิทธิ์สำหรับดึงข้อมูลผู้ใช้จากโทเค็น ID (ID token) และ OIDC userinfo endpoint ทั้ง "ขอบเขต (scope)" และ "การอ้างสิทธิ์ (claim)" เป็นคำศัพท์จากข้อกำหนดของ OAuth 2.0 และ OpenID Connect (OIDC)

โดยสรุป เมื่อคุณร้องขอขอบเขต (scope) ใด คุณจะได้รับข้อมูลการอ้างสิทธิ์ (claim) ที่เกี่ยวข้องในข้อมูลผู้ใช้ เช่น หากคุณร้องขอขอบเขต `email` คุณจะได้รับข้อมูล `email` และ `email_verified` ของผู้ใช้

โดยปกติ Logto SDK จะร้องขอขอบเขตสามรายการเสมอ: `openid`, `profile` และ `offline_access` และไม่สามารถลบขอบเขตเริ่มต้นเหล่านี้ได้ แต่คุณสามารถเพิ่มขอบเขตเพิ่มเติมขณะกำหนดค่า Logto ได้:

<script type="module">
// นำเข้า SDK `@logto/browser` จาก jsdelivr CDN
import LogtoClient from 'https://esm.run/@logto/browser';

// กำหนดอินสแตนซ์ `logtoClient` ให้กับวัตถุ window,
// เพื่อให้สามารถใช้งานแบบ global ในหน้าอื่น ๆ ได้
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // เช่น http://localhost:3001
appId: '<your-application-id>',
scopes: [
UserScope.Email,
UserScope.Phone,
UserScope.CustomData,
UserScope.Identities,
UserScope.Organizations,
],
});
</script>

ต่อไปนี้คือรายการขอบเขต (Scopes) ที่รองรับและการอ้างสิทธิ์ (Claims) ที่เกี่ยวข้อง:

openid

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
substringตัวระบุที่ไม่ซ้ำของผู้ใช้ไม่

profile

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
namestringชื่อเต็มของผู้ใช้ไม่
usernamestringชื่อผู้ใช้ของผู้ใช้ไม่
picturestringURL ของรูปโปรไฟล์ของผู้ใช้ปลายทาง URL นี้ ต้อง อ้างอิงถึงไฟล์รูปภาพ (เช่น ไฟล์ PNG, JPEG หรือ GIF) ไม่ใช่หน้าเว็บที่มีรูปภาพ โปรดทราบว่า URL นี้ ควร อ้างอิงถึงรูปโปรไฟล์ของผู้ใช้ปลายทางที่เหมาะสมสำหรับการแสดงผลเมื่ออธิบายผู้ใช้ปลายทาง ไม่ใช่รูปภาพใด ๆ ที่ผู้ใช้ถ่ายเองไม่
created_atnumberเวลาที่สร้างผู้ใช้ปลายทาง เวลานี้แสดงเป็นจำนวนมิลลิวินาทีตั้งแต่ Unix epoch (1970-01-01T00:00:00Z)ไม่
updated_atnumberเวลาที่ข้อมูลของผู้ใช้ปลายทางถูกอัปเดตล่าสุด เวลานี้แสดงเป็นจำนวนมิลลิวินาทีตั้งแต่ Unix epoch (1970-01-01T00:00:00Z)ไม่

การอ้างสิทธิ์มาตรฐาน อื่น ๆ เช่น family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo, และ locale จะถูกรวมอยู่ในขอบเขต profile ด้วยโดยไม่ต้องร้องขอ endpoint userinfo ความแตกต่างเมื่อเทียบกับการอ้างสิทธิ์ข้างต้นคือ การอ้างสิทธิ์เหล่านี้จะถูกส่งกลับมาเฉพาะเมื่อค่าของมันไม่ว่างเปล่า ในขณะที่การอ้างสิทธิ์ข้างต้นจะส่งกลับ null หากค่าเป็นค่าว่าง

บันทึก:

ต่างจากการอ้างสิทธิ์มาตรฐาน การอ้างสิทธิ์ created_at และ updated_at ใช้หน่วยเป็นมิลลิวินาทีแทนที่จะเป็นวินาที

email

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
emailstringอีเมลของผู้ใช้ไม่
email_verifiedbooleanอีเมลได้รับการยืนยันแล้วหรือไม่ไม่

phone

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
phone_numberstringหมายเลขโทรศัพท์ของผู้ใช้ไม่
phone_number_verifiedbooleanหมายเลขโทรศัพท์ได้รับการยืนยันแล้วหรือไม่ไม่

address

โปรดดูรายละเอียดของการอ้างสิทธิ์ที่อยู่ได้ที่ OpenID Connect Core 1.0

custom_data

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
custom_dataobjectข้อมูลกำหนดเองของผู้ใช้ใช่

identities

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
identitiesobjectข้อมูลตัวตนที่เชื่อมโยงของผู้ใช้ใช่
sso_identitiesarrayข้อมูล SSO ที่เชื่อมโยงของผู้ใช้ใช่

roles

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
rolesstring[]บทบาทของผู้ใช้ไม่

urn:logto:scope:organizations

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
organizationsstring[]รหัสองค์กรที่ผู้ใช้สังกัดไม่
organization_dataobject[]ข้อมูลขององค์กรที่ผู้ใช้สังกัดใช่

urn:logto:scope:organization_roles

ชื่อการอ้างสิทธิ์ประเภทคำอธิบายต้องใช้ userinfo หรือไม่?
organization_rolesstring[]บทบาทของผู้ใช้ในแต่ละองค์กรในรูปแบบ <organization_id>:<role_name>ไม่

เพื่อประสิทธิภาพและขนาดข้อมูล หาก "ต้องใช้ userinfo หรือไม่?" เป็น "ใช่" หมายความว่าการอ้างสิทธิ์นั้นจะไม่ปรากฏในโทเค็น ID แต่จะถูกส่งกลับใน response ของ userinfo endpoint

ทรัพยากร API

เราแนะนำให้อ่าน 🔐 การควบคุมการเข้าถึงตามบทบาท (RBAC) ก่อน เพื่อทำความเข้าใจแนวคิดพื้นฐานของ RBAC ใน Logto และวิธีตั้งค่าทรัพยากร API อย่างถูกต้อง

กำหนดค่า Logto client

เมื่อคุณตั้งค่า ทรัพยากร API (API resources) เรียบร้อยแล้ว คุณสามารถเพิ่มทรัพยากรเหล่านี้ขณะกำหนดค่า Logto ในแอปของคุณได้:

<script type="module">
// นำเข้า SDK `@logto/browser` จาก jsdelivr CDN
import LogtoClient from 'https://esm.run/@logto/browser';

// กำหนดอินสแตนซ์ `logtoClient` ไว้ที่วัตถุ window,
// เพื่อให้สามารถใช้งานแบบ global ในหน้าอื่น ๆ ได้
window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>', // เช่น http://localhost:3001
appId: '<your-application-id>',
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'], // เพิ่มทรัพยากร API
});
</script>

แต่ละ ทรัพยากร API (API resource) จะมี สิทธิ์ (scopes) ของตัวเอง

ตัวอย่างเช่น ทรัพยากร https://shopping.your-app.com/api มีสิทธิ์ shopping:read และ shopping:write และทรัพยากร https://store.your-app.com/api มีสิทธิ์ store:read และ store:write

หากต้องการร้องขอสิทธิ์เหล่านี้ คุณสามารถเพิ่มขณะกำหนดค่า Logto ในแอปของคุณได้:

<script type="module">
// นำเข้า SDK `@logto/browser` จาก jsdelivr CDN
import LogtoClient from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>',
appId: '<your-application-id>',
scopes: ['shopping:read', 'shopping:write', 'store:read', 'store:write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'],
});
</script>

คุณอาจสังเกตได้ว่า ขอบเขต (scopes) ถูกกำหนดแยกจาก ทรัพยากร API (API resources) นี่เป็นเพราะ Resource Indicators for OAuth 2.0 ระบุว่า ขอบเขตสุดท้ายสำหรับคำขอจะเป็นผลคูณคาร์ทีเซียนของขอบเขตทั้งหมดในบริการเป้าหมายทั้งหมด

ดังนั้น ในกรณีข้างต้น ขอบเขต (scopes) สามารถทำให้เรียบง่ายขึ้นจากการกำหนดใน Logto โดยทั้งสอง ทรัพยากร API (API resources) สามารถมีขอบเขต read และ write ได้โดยไม่ต้องมีคำนำหน้า จากนั้น ในการตั้งค่า Logto:

<script type="module">
// นำเข้า SDK `@logto/browser` จาก jsdelivr CDN
import LogtoClient from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>',
appId: '<your-application-id>',
scopes: ['read', 'write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'],
});
</script>

สำหรับแต่ละ ทรัพยากร API (API resource) จะร้องขอทั้งขอบเขต read และ write

บันทึก:

คุณสามารถร้องขอขอบเขต (scopes) ที่ไม่ได้กำหนดไว้ใน ทรัพยากร API (API resources) ได้ เช่น คุณสามารถร้องขอขอบเขต email ได้ แม้ว่า ทรัพยากร API (API resources) จะไม่มีขอบเขต email ให้ ขอบเขตที่ไม่มีจะถูกละเว้นอย่างปลอดภัย

หลังจากลงชื่อเข้าใช้สำเร็จ Logto จะออกขอบเขตที่เหมาะสมให้กับ ทรัพยากร API (API resources) ตามบทบาทของผู้ใช้

ดึงโทเค็นการเข้าถึง (Access token) สำหรับทรัพยากร API

เพื่อดึงโทเค็นการเข้าถึง (Access token) สำหรับทรัพยากร API เฉพาะ คุณสามารถใช้เมธอด getAccessToken ได้ดังนี้:

const isAuthenticated = await logtoClient.isAuthenticated();

if (isAuthenticated) {
// ถ้าได้รับการยืนยันตัวตนแล้ว ให้ดึงโทเค็นการเข้าถึง (access token)
(async () => {
const token = await logtoClient.getAccessToken();
console.log(token); // แสดงโทเค็นการเข้าถึงในคอนโซล
})();
}

เมธอดนี้จะส่งคืนโทเค็นการเข้าถึง (JWT access token) ที่สามารถใช้เข้าถึงทรัพยากร API ได้เมื่อผู้ใช้มีสิทธิ์ที่เกี่ยวข้อง หากโทเค็นการเข้าถึงที่แคชไว้หมดอายุแล้ว เมธอดนี้จะพยายามใช้โทเค็นรีเฟรช (Refresh token) เพื่อขอโทเค็นการเข้าถึงใหม่โดยอัตโนมัติ

ดึงโทเค็นองค์กร (Organization tokens)

หากคุณยังไม่คุ้นเคยกับ องค์กร (Organization) โปรดอ่าน 🏢 องค์กร (หลายผู้เช่า; Multi-tenancy) เพื่อเริ่มต้น

คุณต้องเพิ่ม UserScope.Organizations ขอบเขต (scope) ขณะตั้งค่า Logto client:

import LogtoClient, { UserScope } from 'https://esm.run/@logto/browser';

window.logtoClient = new LogtoClient({
// ...การตั้งค่าอื่น ๆ
scopes: [UserScope.Organizations],
});

เมื่อผู้ใช้ลงชื่อเข้าใช้แล้ว คุณสามารถดึงโทเค็นองค์กร (organization token) สำหรับผู้ใช้ได้:

import { UserScope } from 'https://esm.run/@logto/browser';

const isAuthenticated = await logtoClient.isAuthenticated();

(async () => {
if (!isAuthenticated) {
return;
}
const claims = await logtoClient.getIdTokenClaims();

console.log('การอ้างสิทธิ์ของโทเค็น ID (ID token claims):', claims);
console.log('รหัสองค์กร (Organization IDs):', claims.organizations);

// สมมติว่ามีอย่างน้อยหนึ่งองค์กร ให้ใช้ตัวแรก
const organizationId = claims.organizations[0];
const token = await logtoClient.getOrganizationToken(organizationId);

console.log('โทเค็นการเข้าถึงขององค์กร (Organization access token):', token);
})();

อ่านเพิ่มเติม

กระบวนการสำหรับผู้ใช้ปลายทาง: กระบวนการยืนยันตัวตน, กระบวนการบัญชี, และกระบวนการองค์กร ตั้งค่าตัวเชื่อมต่อ การอนุญาต (Authorization)