Logto คือทางเลือกแทน Auth0 ที่ออกแบบมาสำหรับแอปและผลิตภัณฑ์ SaaS ยุคใหม่ โดยมีทั้งบริการ Cloud และ Open-source เพื่อช่วยให้คุณเปิดตัวระบบการจัดการเอกลักษณ์และการเข้าถึง (IAM) ได้อย่างรวดเร็ว สนุกกับการยืนยันตัวตน (การยืนยันตัวตน), การอนุญาต (การอนุญาต), และการจัดการหลายผู้เช่า ครบจบในที่เดียว
เราแนะนำให้เริ่มต้นด้วย tenant สำหรับการพัฒนาแบบฟรีบน Logto Cloud เพื่อให้คุณสามารถสำรวจฟีเจอร์ทั้งหมดได้อย่างง่ายดาย
ในบทความนี้ เราจะพาคุณไปทีละขั้นตอนเพื่อสร้างประสบการณ์ลงชื่อเข้าใช้ Xiaomi (การยืนยันตัวตนของผู้ใช้) อย่างรวดเร็วด้วย Go และ Logto
ข้อกำหนดเบื้องต้น
- มี Logto instance ที่พร้อมใช้งาน ดู หน้าแนะนำ เพื่อเริ่มต้นใช้งาน
 - มีความรู้พื้นฐานเกี่ยวกับ Go
 - มีบัญชี Xiaomi ที่ใช้งานได้
 
สร้างแอปพลิเคชันใน Logto
Logto สร้างขึ้นบนพื้นฐานของการยืนยันตัวตน OpenID Connect (OIDC) และการอนุญาต OAuth 2.0 โดยรองรับการจัดการข้อมูลระบุตัวตนแบบรวมศูนย์ข้ามหลายแอปพลิเคชัน ซึ่งมักเรียกว่า การลงชื่อเข้าใช้ครั้งเดียว (Single Sign-On; SSO)
ในการสร้างแอปพลิเคชัน เว็บแบบดั้งเดิม ของคุณ เพียงทำตามขั้นตอนเหล่านี้:
- เปิด Logto Console ในส่วน "เริ่มต้นใช้งาน" ให้คลิกที่ลิงก์ "ดูทั้งหมด" เพื่อเปิดรายการเฟรมเวิร์กของแอปพลิเคชัน หรือคุณสามารถไปที่ Logto Console > Applications แล้วคลิกปุ่ม "สร้างแอปพลิเคชัน"
 - ในหน้าต่างที่เปิดขึ้น ให้คลิกที่ส่วน "เว็บแบบดั้งเดิม" หรือกรองเฟรมเวิร์ก "เว็บแบบดั้งเดิม" ทั้งหมดที่มีโดยใช้ช่องกรองด่วนทางซ้ายมือ จากนั้นคลิกที่การ์ดเฟรมเวิร์ก "Go" เพื่อเริ่มสร้างแอปพลิเคชันของคุณ
 - กรอกชื่อแอปพลิเคชัน เช่น "Bookstore" แล้วคลิก "สร้างแอปพลิเคชัน"
 
🎉 เยี่ยมมาก! คุณเพิ่งสร้างแอปพลิเคชันแรกของคุณใน Logto คุณจะเห็นหน้าข้อความแสดงความยินดีซึ่งมีคู่มือการเชื่อมต่ออย่างละเอียด ให้ทำตามคู่มือเพื่อดูประสบการณ์ที่จะเกิดขึ้นในแอปพลิเคชันของคุณ
ผสานรวม Go กับ Logto
- ตัวอย่างสาธิตต่อไปนี้สร้างขึ้นบน Gin Web Framework คุณสามารถผสาน Logto เข้ากับเฟรมเวิร์กอื่น ๆ ได้ด้วยขั้นตอนเดียวกัน
 - โปรเจกต์ตัวอย่าง Go พร้อมใช้งานใน Go SDK repo ของเรา
 
การติดตั้ง
รันคำสั่งในไดเรกทอรีรากของโปรเจกต์:
# ติดตั้งแพ็กเกจ core สำหรับเข้าถึงค่าที่กำหนดไว้ล่วงหน้าและชนิดข้อมูล
go get github.com/logto-io/go/v2/core
# ติดตั้งแพ็กเกจ client สำหรับโต้ตอบกับ Logto
go get github.com/logto-io/go/v2/client
เพิ่มแพ็กเกจ github.com/logto-io/go/v2/core และ github.com/logto-io/go/v2/client ลงในโค้ดแอปพลิเคชันของคุณ:
// main.go
package main
import (
	"github.com/gin-gonic/gin"
	// เพิ่ม dependency
	"github.com/logto-io/go/v2/core"
	"github.com/logto-io/go/v2/client"
)
func main() {
	router := gin.Default()
	router.GET("/", func(c *gin.Context) {
		c.String(200, "Hello Logto!")
	})
	router.Run(":3000")
}
สร้าง session storage
ในเว็บแอปพลิเคชันแบบดั้งเดิม ข้อมูลการยืนยันตัวตนของผู้ใช้จะถูกเก็บไว้ในเซสชันของผู้ใช้
Logto SDK มี Storage interface ให้คุณสามารถสร้างอะแดปเตอร์ Storage ตามเฟรมเวิร์กเว็บของคุณ เพื่อให้ Logto SDK สามารถเก็บข้อมูลการยืนยันตัวตนของผู้ใช้ในเซสชันได้
เรา ไม่แนะนำ ให้ใช้เซสชันที่อิงกับคุกกี้ เนื่องจากข้อมูลการยืนยันตัวตนของผู้ใช้ที่ Logto เก็บไว้อาจมีขนาดเกินขีดจำกัดของคุกกี้ ในตัวอย่างนี้ เราใช้เซสชันที่อยู่ในหน่วยความจำ (memory-based session) คุณสามารถใช้ Redis, MongoDB หรือเทคโนโลยีอื่น ๆ ในการใช้งานจริงเพื่อเก็บเซสชันตามความเหมาะสม
Storage type ใน Logto SDK มีดังนี้:
package client
type Storage interface {
	GetItem(key string) string
	SetItem(key, value string)
}
เราจะใช้ middleware github.com/gin-contrib/sessions เป็นตัวอย่างเพื่อแสดงขั้นตอนนี้
นำ middleware ไปใช้กับแอปพลิเคชัน เพื่อให้เราสามารถดึงเซสชันของผู้ใช้จาก context ของ request ใน route handler ได้:
package main
import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/memstore"
	"github.com/gin-gonic/gin"
	"github.com/logto-io/go/v2/client"
)
func main() {
	router := gin.Default()
	// ในตัวอย่างนี้เราใช้ session ที่อยู่ในหน่วยความจำ
	store := memstore.NewStore([]byte("your session secret"))
	router.Use(sessions.Sessions("logto-session", store))
	router.GET("/", func(ctx *gin.Context) {
		// ดึง session ของผู้ใช้
		session := sessions.Default(ctx)
		// ...
		ctx.String(200, "Hello Logto!")
	})
	router.Run(":3000")
}
สร้างไฟล์ session_storage.go กำหนด SessionStorage และ implement interface Storage ของ Logto SDK:
package main
import (
	"github.com/gin-contrib/sessions"
)
type SessionStorage struct {
	session sessions.Session
}
func (storage *SessionStorage) GetItem(key string) string {
	value := storage.session.Get(key)
	if value == nil {
		return ""
	}
	return value.(string)
}
func (storage *SessionStorage) SetItem(key, value string) {
	storage.session.Set(key, value)
	storage.session.Save()
}
ตอนนี้ ใน route handler คุณสามารถสร้าง session storage สำหรับ Logto ได้ดังนี้:
session := sessions.Default(ctx)
sessionStorage := &SessionStorage{session: session}
เริ่มต้น LogtoClient
ก่อนอื่น สร้าง Logto config:
func main() {
	// ...
	logtoConfig := &client.LogtoConfig{
		Endpoint:  "<your-logto-endpoint>", // เช่น http://localhost:3001
		AppId:     "<your-application-id>",
		AppSecret: "<your-application-secret>",
	}
	// ...
}
คุณสามารถค้นหาและคัดลอก "App Secret" ได้จากหน้ารายละเอียดแอปพลิเคชันใน Admin Console:

จากนั้น คุณสามารถสร้าง LogtoClient สำหรับแต่ละคำขอของผู้ใช้โดยใช้ Logto config ข้างต้น:
func main() {
	// ...
	router.GET("/", func(ctx *gin.Context) {
		// สร้าง LogtoClient
		session := sessions.Default(ctx)
		logtoClient := client.NewLogtoClient(
			logtoConfig,
			&SessionStorage{session: session},
		)
		// ใช้ Logto เพื่อควบคุมเนื้อหาของหน้าแรก
		authState := "คุณยังไม่ได้เข้าสู่ระบบเว็บไซต์นี้ :("
		if logtoClient.IsAuthenticated() {
			authState = "คุณได้เข้าสู่ระบบเว็บไซต์นี้แล้ว! :)"
		}
		homePage := `<h1>Hello Logto</h1>` +
			"<div>" + authState + "</div>"
		ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(homePage))
	})
	// ...
}
สร้างเส้นทาง sign-in
หลังจากกำหนดค่า redirect URI แล้ว เราจะเพิ่ม route sign-in เพื่อจัดการคำขอลงชื่อเข้าใช้ และเพิ่มลิงก์สำหรับลงชื่อเข้าใช้ในหน้าแรกด้วย:
func main() {
	// ...
	// เพิ่มลิงก์สำหรับดำเนินการคำขอลงชื่อเข้าใช้ในหน้าแรก
	router.GET("/", func(ctx *gin.Context) {
		// ...
		homePage := `<h1>Hello Logto</h1>` +
			"<div>" + authState + "</div>" +
			// เพิ่มลิงก์
			`<div><a href="/sign-in">Sign In</a></div>`
		ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(homePage))
	})
	// เพิ่ม route สำหรับจัดการคำขอลงชื่อเข้าใช้
	router.GET("/sign-in", func(ctx *gin.Context) {
		session := sessions.Default(ctx)
		logtoClient := client.NewLogtoClient(
			logtoConfig,
			&SessionStorage{session: session},
		)
		// คำขอลงชื่อเข้าใช้จะถูกจัดการโดย Logto
		// ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยัง Redirect URI หลังจากลงชื่อเข้าใช้สำเร็จ
		signInUri, err := logtoClient.SignIn("http://localhost:3000/callback")
		if err != nil {
			ctx.String(http.StatusInternalServerError, err.Error())
			return
		}
		// เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าลงชื่อเข้าใช้ของ Logto
		ctx.Redirect(http.StatusTemporaryRedirect, signInUri)
	})
	// ...
}
ตอนนี้ เมื่อผู้ใช้ของคุณเข้าชม http://localhost:3000/sign-in ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังหน้าลงชื่อเข้าใช้ของ Logto
สร้างเส้นทาง callback
เมื่อผู้ใช้ลงชื่อเข้าใช้สำเร็จบนหน้าลงชื่อเข้าใช้ของ Logto แล้ว Logto จะเปลี่ยนเส้นทาง (redirect) ผู้ใช้ไปยัง Redirect URI
เนื่องจาก Redirect URI คือ http://localhost:3000/callback เราจึงเพิ่ม route /callback เพื่อจัดการ callback หลังจากลงชื่อเข้าใช้
func main() {
	// ...
	// เพิ่ม route สำหรับจัดการคำขอ callback หลังลงชื่อเข้าใช้
	router.GET("/callback", func(ctx *gin.Context) {
		session := sessions.Default(ctx)
		logtoClient := client.NewLogtoClient(
			logtoConfig,
			&SessionStorage{session: session},
		)
		// คำขอ callback หลังลงชื่อเข้าใช้จะถูกจัดการโดย Logto
		err := logtoClient.HandleSignInCallback(ctx.Request)
		if err != nil {
			ctx.String(http.StatusInternalServerError, err.Error())
			return
		}
		// เปลี่ยนหน้าไปยังหน้าที่นักพัฒนาระบุไว้
		// ตัวอย่างนี้จะพาผู้ใช้กลับไปยังหน้าแรก
		ctx.Redirect(http.StatusTemporaryRedirect, "/")
	})
	// ...
}
สร้างเส้นทาง sign-out
เช่นเดียวกับขั้นตอนการลงชื่อเข้าใช้ เมื่อผู้ใช้ลงชื่อออก Logto จะเปลี่ยนเส้นทางผู้ใช้ไปยัง post sign-out redirect URI
ตอนนี้ มาเพิ่ม route sign-out เพื่อจัดการคำขอลงชื่อออก และเพิ่มลิงก์สำหรับลงชื่อออกในหน้าแรกด้วย:
func main() {
	// ...
	// เพิ่มลิงก์สำหรับดำเนินการลงชื่อออกในหน้าแรก
	router.GET("/", func(ctx *gin.Context) {
		// ...
		homePage := `<h1>Hello Logto</h1>` +
			"<div>" + authState + "</div>" +
			`<div><a href="/sign-in">Sign In</a></div>` +
			// เพิ่มลิงก์
			`<div><a href="/sign-out">Sign Out</a></div>`
		ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(homePage))
	})
	// เพิ่ม route สำหรับจัดการคำขอลงชื่อออก
	router.GET("/sign-out", func(ctx *gin.Context) {
		session := sessions.Default(ctx)
		logtoClient := client.NewLogtoClient(
			logtoConfig,
			&SessionStorage{session: session},
		)
		// คำขอลงชื่อออกจะถูกจัดการโดย Logto
		// ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยัง Post Sign-out Redirect URI หลังจากลงชื่อออก
		signOutUri, signOutErr := logtoClient.SignOut("http://localhost:3000")
		if signOutErr != nil {
			ctx.String(http.StatusOK, signOutErr.Error())
			return
		}
		ctx.Redirect(http.StatusTemporaryRedirect, signOutUri)
	})
	// ...
}
หลังจากผู้ใช้ดำเนินการลงชื่อออก Logto จะล้างข้อมูลการยืนยันตัวตน (authentication) ของผู้ใช้ทั้งหมดใน session
จุดตรวจสอบ: ทดสอบแอปพลิเคชันของคุณ
ตอนนี้คุณสามารถทดสอบแอปพลิเคชันของคุณได้แล้ว:
- รันแอปพลิเคชันของคุณ คุณจะเห็นปุ่มลงชื่อเข้าใช้
 - คลิกปุ่มลงชื่อเข้าใช้ SDK จะเริ่มกระบวนการลงชื่อเข้าใช้และเปลี่ยนเส้นทางคุณไปยังหน้าลงชื่อเข้าใช้ของ Logto
 - หลังจากที่คุณลงชื่อเข้าใช้แล้ว คุณจะถูกเปลี่ยนเส้นทางกลับไปยังแอปพลิเคชันของคุณและเห็นปุ่มลงชื่อออก
 - คลิกปุ่มลงชื่อออกเพื่อเคลียร์ที่เก็บโทเค็นและออกจากระบบ
 
เพิ่มตัวเชื่อมต่อ Xiaomi
เพื่อเปิดใช้งานการลงชื่อเข้าใช้อย่างรวดเร็วและเพิ่มอัตราการเปลี่ยนผู้ใช้ ให้เชื่อมต่อกับ Go ในฐานะผู้ให้บริการข้อมูลระบุตัวตน (Identity provider) ตัวเชื่อมต่อโซเชียลของ Logto ช่วยให้คุณสร้างการเชื่อมต่อนี้ได้ภายในไม่กี่นาที โดยสามารถกรอกพารามิเตอร์ได้หลายค่า
ในการเพิ่มตัวเชื่อมต่อโซเชียล ให้ทำตามขั้นตอนดังนี้:
- ไปที่ Console > Connectors > Social Connectors
 - คลิก "Add social connector" และเลือก "Xiaomi"
 - ทำตามคู่มือ README กรอกข้อมูลที่จำเป็น และปรับแต่งการตั้งค่า
 
หากคุณกำลังทำตามคู่มือ Connector แบบ in-place คุณสามารถข้ามส่วนถัดไปได้
ตั้งค่า Xiaomi OAuth app
เริ่มต้นใช้งาน
- สร้างบัญชีนักพัฒนาที่ Xiaomi Open Platform
 - ไปที่ Xiaomi Account Service
 - สร้างแอปพลิเคชันใหม่หากคุณยังไม่มี
 
ตั้งค่าแอปพลิเคชัน Xiaomi OAuth
- ไปที่ Xiaomi Account Service
 - ตั้งค่าการตั้งค่า OAuth:
- เปิดแอปพลิเคชันที่คุณต้องการใช้สำหรับเข้าสู่ระบบ คลิกที่ "Callback URL" (หากคุณยังไม่ได้แก้ไข callback URL จะปรากฏเป็น "Enabled")
 - เพิ่ม URL callback สำหรับการอนุญาต: 
${your_logto_origin}/callback/${connector_id} connector_idสามารถดูได้ที่ด้านบนของหน้ารายละเอียดตัวเชื่อมต่อใน Logto Console
 - รับ 
AppIDและAppSecretจากหน้ารายละเอียดแอปพลิเคชัน - กรอกข้อมูลในช่อง 
clientIdและclientSecretใน Logto Console ด้วยค่าจากขั้นตอนที่ 3 - การตั้งค่าเพิ่มเติม (ไม่บังคับ):
skipConfirm: ข้ามหน้าการยืนยันการอนุญาตของ Xiaomi หรือไม่ เมื่อผู้ใช้เข้าสู่ระบบ Xiaomi อยู่แล้ว ค่าเริ่มต้นคือ false
 
คำอธิบายขอบเขต (Scopes)
โดยค่าเริ่มต้น ตัวเชื่อมต่อจะร้องขอขอบเขตดังต่อไปนี้:
1: อ่านโปรไฟล์ผู้ใช้
ขอบเขตที่สามารถใช้ได้:
| ค่า Scope | คำอธิบาย | API Interface | 
|---|---|---|
| 1 | รับโปรไฟล์ผู้ใช้ | user/profile | 
| 3 | รับ user open_id | user/openIdV2 | 
| 1000 | รับข้อมูลเราเตอร์ Xiaomi | Mi Router | 
| 1001 | เข้าถึงข้อมูลเราเตอร์ Xiaomi ทั้งหมด | Mi Router | 
| 2001 | เข้าถึงปฏิทินคลาวด์ Xiaomi | Mi Cloud | 
| 2002 | เข้าถึงนาฬิกาปลุกคลาวด์ Xiaomi | Mi Cloud | 
| 6000 | ใช้บริการสมาร์ทโฮม Mi Home | Mi Home | 
| 6002 | เพิ่มอุปกรณ์บุคคลที่สามใน Mi Home | Mi Home | 
| 6003 | ควบคุมอุปกรณ์ Xiaomi ด้วย Alexa | Mi Home | 
| 6004 | บริการบุคคลที่สามเข้าถึงอุปกรณ์ Xiaomi | Mi Home | 
| 7000 | ติดตามบัญชี Yellow Pages service | Mi Cloud | 
| 11000 | รับรูปภาพคลาวด์ Xiaomi | Mi Cloud | 
| 12001 | บันทึกข้อมูลแอปลงใน Mi Cloud | Mi Cloud | 
| 12005 | ใช้บริการ ECG สุขภาพ | Health | 
| 16000 | รับบัตรผ่าน Mi Wallet | app/get_pass | 
| 20000 | เปิดใช้งานบริการเสียง XiaoAI | XiaoAI | 
| 40000 | เปิดใช้งานบริการ AI คลาวด์ | Internal Use | 
สามารถตั้งค่าขอบเขตหลายค่าได้โดยคั่นด้วยช่องว่าง เช่น: 1 3 6000
ทดสอบตัวเชื่อมต่อ Xiaomi
เสร็จเรียบร้อย อย่าลืม เปิดใช้งานการเข้าสู่ระบบโซเชียล ในประสบการณ์การลงชื่อเข้าใช้
บันทึกการตั้งค่าของคุณ
โปรดตรวจสอบให้แน่ใจว่าคุณได้กรอกค่าที่จำเป็นในพื้นที่การตั้งค่าตัวเชื่อมต่อ Logto เรียบร้อยแล้ว คลิก "บันทึกและเสร็จสิ้น" (หรือ "บันทึกการเปลี่ยนแปลง") และตัวเชื่อมต่อ Xiaomi ควรพร้อมใช้งานแล้ว
เปิดใช้งานตัวเชื่อมต่อ Xiaomi ในประสบการณ์การลงชื่อเข้าใช้
เมื่อคุณสร้างตัวเชื่อมต่อโซเชียลสำเร็จแล้ว คุณสามารถเปิดใช้งานเป็นปุ่ม "ดำเนินการต่อด้วย Xiaomi" ในประสบการณ์การลงชื่อเข้าใช้ (Sign-in Experience) ได้
- ไปที่ Console > ประสบการณ์การลงชื่อเข้าใช้ > สมัครและลงชื่อเข้าใช้
 - (ไม่บังคับ) เลือก "ไม่เกี่ยวข้อง" สำหรับตัวระบุการสมัคร หากคุณต้องการเฉพาะการเข้าสู่ระบบโซเชียล
 - เพิ่มตัวเชื่อมต่อ Xiaomi ที่ตั้งค่าไว้แล้วในส่วน "เข้าสู่ระบบโซเชียล" (Social sign-in)
 
การทดสอบและการตรวจสอบความถูกต้อง
กลับไปที่แอป Go ของคุณ ตอนนี้คุณควรจะสามารถลงชื่อเข้าใช้ด้วย Xiaomi ได้แล้ว ขอให้สนุก!
อ่านเพิ่มเติม
กระบวนการสำหรับผู้ใช้ปลายทาง: Logto มีโฟลว์การยืนยันตัวตนสำเร็จรูปพร้อมใช้งาน รวมถึง MFA และ Enterprise SSO พร้อม API อันทรงพลังสำหรับการปรับแต่งการตั้งค่าบัญชี การตรวจสอบความปลอดภัย และประสบการณ์แบบหลายผู้เช่า (multi-tenant) ได้อย่างยืดหยุ่น
การอนุญาต (Authorization): การอนุญาต (Authorization) กำหนดว่าผู้ใช้สามารถทำอะไรหรือเข้าถึงทรัพยากรใดได้บ้างหลังจากได้รับการยืนยันตัวตนแล้ว สำรวจวิธีปกป้อง API ของคุณสำหรับแอปเนทีฟและแอปหน้าเดียว (SPA) และการใช้งานการควบคุมการเข้าถึงตามบทบาท (RBAC)
องค์กร (Organizations): ฟีเจอร์องค์กรมีประสิทธิภาพอย่างยิ่งใน SaaS แบบหลายผู้เช่าและแอป B2B โดยช่วยให้สร้างผู้เช่า จัดการสมาชิก RBAC ระดับองค์กร และ Just-in-Time Provisioning ได้
ชุดบทความ Customer IAM: บทความต่อเนื่องเกี่ยวกับการจัดการข้อมูลระบุตัวตนและการเข้าถึงของลูกค้า (Customer IAM) ตั้งแต่ระดับพื้นฐาน 101 ไปจนถึงหัวข้อขั้นสูงและอื่น ๆ