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

รูปแบบการตรวจสอบสิทธิ์ Backend for Frontend (BFF) เป็นวิธีการออกแบบที่มุ่งเน้นไปที่การจัดหาแบ็กเอนด์เฉพาะเพื่อจัดการและจัดการกับข้อกำหนดในการตรวจสอบสิทธิ์และความท้าทายทั้งหมดของแอปพลิเคชันส่วนหน้า (SPA)

วัตถุประสงค์

วัตถุประสงค์หลักของบล็อกเทคโนโลยีคือการให้ความรู้แก่ผู้อ่านเกี่ยวกับรูปแบบการตรวจสอบสิทธิ์ Backend for Frontend (BFF) และการนำไปใช้ในภาษาการเขียนโปรแกรม Go บล็อกนี้จะให้ภาพรวมที่ครอบคลุมของรูปแบบ คุณประโยชน์ของรูปแบบ และความท้าทายที่แก้ไขในบริบทของการสร้างระบบการตรวจสอบสิทธิ์สำหรับแอปพลิเคชันส่วนหน้า

ประวัติ

โดยทั่วไปแล้ว SPA จะใช้การรับรองความถูกต้องโดยใช้โทเค็น เช่น JSON Web Tokens (JWT) เพื่อรับรองความถูกต้องและให้สิทธิ์ผู้ใช้ อย่างไรก็ตาม การจัดการโทเค็นอย่างปลอดภัยใน SPA อาจเป็นเรื่องที่ท้าทาย การจัดเก็บโทเค็นในพื้นที่จัดเก็บข้อมูลฝั่งไคลเอ็นต์ (เช่น พื้นที่จัดเก็บในเครื่องหรือคุกกี้) อาจทำให้โทเค็นถูกโจมตีได้ เช่น การปลอมแปลงคำขอข้ามไซต์ (CSRF) นักพัฒนาต้องใช้มาตรการรักษาความปลอดภัยที่เข้มงวดเพื่อปกป้องโทเค็นและป้องกันการเข้าถึงหรือการใช้ในทางที่ผิดโดยไม่ได้รับอนุญาต

รูปแบบ BFF แก้ปัญหานี้โดยการแนะนำเลเยอร์ระดับกลาง — แบ็กเอนด์สำหรับส่วนหน้า เลเยอร์นี้ทำหน้าที่เป็นพร็อกซีระหว่างไคลเอ็นต์ส่วนหน้าและบริการแบ็กเอนด์หลัก จัดการข้อกังวลที่เกี่ยวข้องกับการรับรองความถูกต้อง และจัดเตรียมอินเทอร์เฟซการรับรองความถูกต้องแบบพิเศษ

แผนภาพการไหล

1. เมื่อส่วนหน้าจำเป็นต้องตรวจสอบสิทธิ์ผู้ใช้ ระบบจะเรียกจุดสิ้นสุด API (/login) บน BFF เพื่อเริ่มการจับมือเข้าสู่ระบบ

2. BFF ใช้ OAuth2 Authorization Code Flow เพื่อเชื่อมต่อกับ Auth0 เพื่อตรวจสอบสิทธิ์และให้สิทธิ์ผู้ใช้ และรับ ID และโทเค็นการเข้าถึง

3. แบ็กเอนด์เก็บโทเค็นของผู้ใช้ไว้ในแคช

4. มีการออกคุกกี้ที่เข้ารหัสสำหรับส่วนหน้าที่แสดงถึงเซสชันการตรวจสอบสิทธิ์ผู้ใช้

5. เมื่อส่วนหน้าจำเป็นต้องเรียกใช้ API ภายนอก ส่วนหน้าจะส่งผ่านคุกกี้ที่เข้ารหัสไปยัง BFF พร้อมด้วย URL และข้อมูลเพื่อเรียกใช้ API

6. BFF ดึงโทเค็นการเข้าถึงจากแคชและทำการเรียกไปยัง API แบ็กเอนด์ รวมถึงโทเค็นนั้นบนส่วนหัวของการอนุญาต

7. เมื่อ API ภายนอกส่งคืนการตอบกลับไปยัง BFF API นี้จะส่งต่อการตอบกลับนั้นกลับไปยังส่วนหน้า

การนำไปปฏิบัติ

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

ตามข้อกำหนดเบื้องต้นในการทำความเข้าใจโซลูชันที่นำเสนออย่างถ่องแท้ ฉันขอแนะนำให้คุณทำความเข้าใจเกี่ยวกับหัวข้อต่อไปนี้ หากยังไม่ทราบหัวข้อเหล่านี้

1. ลงทะเบียนแอปพลิเคชันเว็บปกติใน Auth0

2. “งาน Iris Web Frame”

3. ขั้นตอนรหัสการอนุญาต

โครงสร้างโครงการ

เริ่ม

เพื่อเริ่มต้นกระบวนการนำไปใช้งาน ฉันอ้างอิงถึง Auth0 Guide เพื่อลงทะเบียนเว็บแอปพลิเคชันของฉัน ตามคำแนะนำ ฉันตั้งค่าการตรวจสอบสิทธิ์ผู้ใช้สำหรับเว็บแอปพลิเคชันโดยใช้ Auth0 ได้สำเร็จ ด้วยฟังก์ชันการตรวจสอบสิทธิ์เริ่มต้น ฉันจึงดำเนินการแก้ไขโค้ดเพื่อรวมรูปแบบการตรวจสอบสิทธิ์ Backend for Frontend (BFF) router.go

เราเตอร์.go

ใน router.go ฉันกำหนดเส้นทางทั้งหมดที่จำเป็นในการตรวจสอบสิทธิ์และอนุญาตผู้ใช้

  • `/login`: จุดสิ้นสุดนี้จะถูกทริกเกอร์เมื่อผู้ใช้คลิกที่ปุ่มเข้าสู่ระบบในส่วนหน้า
  • `/logout`: ส่วนหน้ากำหนดเส้นทางไปยังปลายทางนี้เมื่อผู้ใช้คลิกที่ปุ่มออกจากระบบ
  • `/callback`: ตำแหน่งข้อมูลนี้รับผิดชอบกระบวนการแลกเปลี่ยนโทเค็นด้วยรหัสอนุญาต
  • `/shorten`: นี่เป็นหนึ่งใน API แบ็กเอนด์ที่ส่วนหน้าจะใช้
type router struct{}

func (router *router) InitRouter(auth *authenticator.Authenticator, redis interfaces.IRedisLayer) *iris.Application {
 app := iris.New()

 loginHandler := controller.LoginHandler{Auth: auth}
 callbackHandler := controller.CallbackHandler{Auth: auth, RedisClient: redis}
 logoutHandler := controller.LogoutHandler{RedisClient: redis}
 backendApiHandler := controller.BackendApiHandler{RedisClient: redis}
 middlewareHandler := middleware.MiddlewareHandler{RedisClient: redis}

 app.Get("/login", loginHandler.Login)
 app.Get("/callback", callbackHandler.Callback)
 app.Get("/logout", logoutHandler.Logout)

 // Backend Api
 app.Post("/shorten", middlewareHandler.IsAuthenticated, backendApiHandler.WriterRedirect)

 return app
}

สิ่งสำคัญที่ควรทราบคือการใช้ตัวจัดการ middlewareHandler.IsAuthenticated ในเส้นทาง API แบ็กเอนด์ ตัวจัดการนี้มีบทบาทสำคัญในการตรวจสอบโปรไฟล์การเข้าสู่ระบบของผู้ใช้ คุณสามารถดูรายละเอียดการใช้งานได้ในส่วนมิดเดิลแวร์

คอนโทรลเลอร์

ในคอนโทรลเลอร์ ฉันได้สรุปตรรกะสำหรับเส้นทางทั้งหมดที่กล่าวถึงก่อนหน้านี้ นี่คือที่ที่มีการกำหนดและจัดการรายละเอียดการใช้งานสำหรับแต่ละเส้นทาง

  • login.go
    ในเส้นทางการเข้าสู่ระบบ ตัวจัดการจะเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าเข้าสู่ระบบสากลของ Identity Provider (IDP) หน้านี้อนุญาตให้ผู้ใช้ดำเนินการลงชื่อเพียงครั้งเดียวและให้ความยินยอม
    หลังจากที่ผู้ใช้ให้ความยินยอมในหน้าเข้าสู่ระบบ IDP Universal หน้าเว็บจะถูกเปลี่ยนเส้นทางกลับไปยังตำแหน่งข้อมูล /callback พร้อมด้วยรหัสอนุญาต
type LoginHandler struct {
 Auth *authenticator.Authenticator
}

func (l *LoginHandler) Login(ctx iris.Context) {
 ctx.Redirect(l.Auth.AuthCodeURL(state, oauth2.SetAuthURLParam("audience", config.EnvVariables.Auth0Audience)), http.StatusTemporaryRedirect)
}

พารามิเตอร์ผู้ชมมีบทบาทสำคัญในการอ้างสิทธิ์ผู้ชมภายในเพย์โหลด ซึ่งช่วยในการอนุญาตผู้ใช้ เพื่อความเข้าใจที่ละเอียดยิ่งขึ้น ขอแนะนำให้อ้างอิงถึง "แหล่งข้อมูลเพิ่มเติม"
ความท้าทายที่สำคัญคือการรวมพารามิเตอร์ URL ผู้ชมไว้ในฟังก์ชัน l.Auth.AuthCodeURL() เมื่อตรวจสอบ "ซอร์สโค้ด" ของ "แพ็คเกจ oauth2" และทำความเข้าใจการใช้งาน ฉันได้รับข้อมูลเชิงลึกเกี่ยวกับวิธีส่งพารามิเตอร์ผู้ชมโดยใช้ oauth2.SetAuthURLParam()

  • callback.go
    หลังจากที่ผู้ใช้เยี่ยมชมเส้นทาง /login แล้ว URL /callback จะถูกเรียก โดยส่งสถานะและรหัสการอนุญาตเป็นพารามิเตอร์
    ตัวจัดการที่รับผิดชอบ /callback URL จะตรวจสอบค่าของพารามิเตอร์ state เพื่อให้มั่นใจในความสมบูรณ์และความปลอดภัย
    เมื่อค่าสถานะได้รับการตรวจสอบเรียบร้อยแล้ว ตัวจัดการจะดำเนินการแลกเปลี่ยนรหัสการอนุญาตสำหรับโทเค็นการเข้าถึง
    นอกเหนือจากการแลกเปลี่ยนโทเค็นแล้ว ตัวจัดการยังดำเนินขั้นตอนที่จำเป็นเพื่อบันทึกโทเค็นและข้อมูลโปรไฟล์ผู้ใช้ใน Redis ซึ่งเป็นที่เก็บข้อมูลที่ใช้กันทั่วไปสำหรับการแคชและการจัดการเซสชัน
type CallbackHandler struct {
 Auth        *authenticator.Authenticator
 RedisClient interfaces.IRedisLayer
}

func (c *CallbackHandler) Callback(ctx iris.Context) {
 if ctx.URLParam("state") != state {
  ctx.StopWithJSON(http.StatusBadRequest, "Invalid state parameter.")
  return
 }

 // Exchange an authorization code for a token.
 token, err := c.Auth.Exchange(ctx.Request().Context(), ctx.URLParam("code"))
 if err != nil {
  ctx.StopWithJSON(http.StatusUnauthorized, "Failed to convert an authorization code into a token.")
  return
 }

 idToken, err := c.Auth.VerifyIDToken(ctx.Request().Context(), token)
 if err != nil {
  ctx.StopWithJSON(http.StatusInternalServerError, "Failed to verify ID Token.")
  return
 }

 var profile map[string]interface{}
 if err := idToken.Claims(&profile); err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 err = c.RedisClient.SetKeyValue(profile["email"].(string)+"_token", token.AccessToken, 24*time.Hour)
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }
 err = c.RedisClient.HSetKeyValue(profile["email"].(string)+"_profile", profile, 24*time.Hour)
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 ctx.SetCookieKV("logged_id_email", profile["email"].(string))

 // Redirect to logged in page.
 ctx.Redirect(config.EnvVariables.FrontendURL, http.StatusTemporaryRedirect)
}

เพื่อจัดเก็บโทเค็นและข้อมูลโปรไฟล์ ฉันได้ติดตั้ง "Redis" เป็นเลเยอร์แคช ฉันสร้างคีย์สำหรับผู้ใช้แต่ละคนโดยนำหน้าด้วยที่อยู่อีเมลเพื่อให้แน่ใจว่าไม่ซ้ำกันและดึงข้อมูลได้ง่าย
นอกจากนี้ ฟังก์ชัน ctx.SetCookieKV() ยังใช้เพื่อตั้งค่าการเข้ารหัส คุกกี้ "HTTP เท่านั้น" ฟรอนต์เอนด์จะส่งคุกกี้นี้ในภายหลังเมื่อทำการเรียกไปยัง API แบ็กเอนด์

  • logout.go
    เมื่อผู้ใช้คลิกที่ปุ่มออกจากระบบ ตัวจัดการการออกจากระบบจะดำเนินการหลักสองประการ ประการแรก จะล้างค่าที่แคชไว้ทั้งหมด เพื่อให้แน่ใจว่าโทเค็นที่เก็บไว้หรือข้อมูลโปรไฟล์ผู้ใช้จะถูกลบออก ประการที่สอง เริ่มต้นกระบวนการออกจากระบบด้วย Auth0 (IDP) ซึ่งจะออกจากระบบผู้ใช้จากผู้ให้บริการข้อมูลประจำตัวอย่างมีประสิทธิภาพ
 type LogoutHandler struct {
 RedisClient interfaces.IRedisLayer
}

func (l *LogoutHandler) Logout(ctx iris.Context) {
 userCookie := ctx.GetCookie("logged_id_email")
 if userCookie == "" {
  ctx.StopWithError(iris.StatusUnauthorized, errors.New("please make sure user is logged in"))
  return
 }

 // delete token key
 err := l.RedisClient.DeleteKey(userCookie + "_token")
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 // delete profile key
 err = l.RedisClient.DeleteKey(userCookie + "_profile")
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 logoutUrl, err := url.Parse("https://" + config.EnvVariables.Auth0Domain + "/v2/logout")
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 returnTo, err := url.Parse(config.EnvVariables.ShortifyFrontendDomain)
 if err != nil {
  ctx.StopWithError(http.StatusInternalServerError, err)
  return
 }

 // remove the logged_id_email http-only cookie from context
 ctx.RemoveCookie("logged_id_email")

 parameters := url.Values{}
 parameters.Add("returnTo", returnTo.String())
 parameters.Add("client_id", config.EnvVariables.Auth0ClientID)
 logoutUrl.RawQuery = parameters.Encode()

 ctx.Redirect(logoutUrl.String(), http.StatusTemporaryRedirect)
}

หากต้องการลบข้อมูลที่แคชไว้ รวมถึงโปรไฟล์ผู้ใช้และโทเค็นที่จัดเก็บไว้ใน Redis ฉันใช้ฟังก์ชัน RedisClient.DeleteKey() เพื่อให้แน่ใจว่าข้อมูลที่เกี่ยวข้องจะถูกลบออกจากแคช นอกจากนี้ การเรียก /v2/logout API ของ Auth0 ยังช่วยให้เราออกจากระบบผู้ใช้จาก Auth0 ได้อย่างมีประสิทธิภาพอีกด้วย
หากต้องการลบคุกกี้เฉพาะ ctx.RemoveCookie() ถูกใช้ ฟังก์ชันนี้กำหนดเป้าหมายและลบคุกกี้ 'logged_id_email' โดยเฉพาะ ซึ่งตั้งค่าไว้ตั้งแต่แรกในระหว่างตัวจัดการ /callback

  • backendApi.go
    เมื่อฟรอนต์เอนด์ส่งคำขอไปยัง API แบ็กเอนด์ตัวใดตัวหนึ่ง แบ็กเอนด์สำหรับฟรอนต์เอนด์ (BFF) จะทำให้แน่ใจว่าจะดึงโทเค็นผู้ใช้จาก แคช โทเค็นนี้จำเป็นสำหรับวัตถุประสงค์ในการตรวจสอบสิทธิ์และการอนุญาต
    จากนั้น BFF จะเพิ่มโทเค็นที่ดึงข้อมูลไปยังส่วนหัวการอนุญาตของคำขอและส่งต่อไปยัง API แบ็กเอนด์
    เมื่อ API แบ็กเอนด์ประมวลผลคำขอและสร้าง การตอบสนอง BFF ทำหน้าที่เป็นพร็อกซีและส่งการตอบกลับกลับไปยังส่วนหน้า ทำให้สามารถสื่อสารได้อย่างราบรื่นระหว่างส่วนหน้าและส่วนหลัง
type BackendApiHandler struct {
 RedisClient interfaces.IRedisLayer
}

func (w *BackendApiHandler) WriterRedirect(ctx iris.Context) {
 raw, err := ctx.User().GetRaw()
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }
 profile := raw.(map[string]string)
 email := profile["email"]

 token, err := w.RedisClient.GetKeyValue(email + "_token")
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }

 client := &http.Client{}
 req, err := http.NewRequest(ctx.Request().Method, config.EnvVariables.BackendApi, ctx.Request().Body)
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }

 req.Header.Add("Authorization", "Bearer "+token)
 req.Header.Add("Content-Type", "application/json")

 res, err := client.Do(req)
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }
 defer res.Body.Close()

 body, err := io.ReadAll(res.Body)
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }

 var respBody map[string]interface{}
 err = json.Unmarshal(body, &respBody)
 if err != nil {
  ctx.StopWithError(500, err)
  return
 }

 ctx.StopWithJSON(res.StatusCode, respBody)
}

โปรดทราบว่า ctx.User().GetRaw() จะดึงข้อมูลโปรไฟล์ผู้ใช้ที่ตั้งค่าระหว่างมิดเดิลแวร์ ตัวจัดการ IsAuthenticated() ที่กำหนดไว้ด้านล่าง ด้วยความช่วยเหลือของอีเมลจาก ctx.User() ฉันได้รับโทเค็นจากแคช Redis และเพิ่มส่วนหัวการอนุญาต

มิดเดิลแวร์

มิดเดิลแวร์มีบทบาทสำคัญในการตรวจสอบความถูกต้องของคุกกี้ที่เข้ารหัสที่ส่งจากฟรอนต์เอนด์พร้อมกับคำขอ API และยังตรวจสอบว่าผู้ใช้เข้าสู่ระบบหรือไม่

  • isAuhtenticated.go
type MiddlewareHandler struct {
 RedisClient interfaces.IRedisLayer
}

// IsAuthenticated is a middleware that checks if
// the user has already been authenticated previously.
func (m *MiddlewareHandler) IsAuthenticated(ctx iris.Context) {
 userCookie := ctx.GetCookie("logged_id_email")
 if userCookie == "" {
  ctx.StopWithError(iris.StatusUnauthorized, errors.New("please make sure user is logged in"))
  return
 }

 value, err := m.RedisClient.HGetKeyValue(userCookie + "_profile")
 if err != nil || value == nil {
  ctx.StopWithError(iris.StatusUnauthorized, errors.New("please make sure user is logged in"))
  return
 }

 ctx.SetUser(value)
 ctx.Next()
}

ด้วยการใช้ ctx.SetUser() ข้อมูลโปรไฟล์ผู้ใช้จะถูกจัดเก็บไว้ในบริบทของ Iris ข้อมูลนี้จะสามารถเข้าถึงได้และสามารถใช้งานได้โดยตัวจัดการ API แบ็กเอนด์ในระหว่างการประมวลผลคำขอ

ตัวรับรองความถูกต้อง

Authenticator เริ่มต้นอินสแตนซ์ใหม่ของผู้ให้บริการ Oauth2

// Authenticator is used to authenticate our users.
type Authenticator struct {
 *oidc.Provider
 oauth2.Config
}

// New instantiates the *Authenticator.
func New() (*Authenticator, error) {
 provider, err := oidc.NewProvider(
  context.Background(),
  "https://"+config.EnvVariables.Auth0Domain+"/",
 )
 if err != nil {
  return nil, err
 }

 conf := oauth2.Config{
  ClientID:     config.EnvVariables.Auth0ClientID,
  ClientSecret: config.EnvVariables.Auth0ClientSecret,
  RedirectURL:  config.EnvVariables.Auth0CallbackURL,
  Endpoint:     provider.Endpoint(),
  Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
 }

 return &Authenticator{
  Provider: provider,
  Config:   conf,
 }, nil
}

// VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
 rawIDToken, ok := token.Extra("id_token").(string)
 if !ok {
  return nil, errors.New("no id_token field in oauth2 token")
 }

 oidcConfig := &oidc.Config{
  ClientID: a.ClientID,
 }

 return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
}

จำเป็นอย่างยิ่งที่จะต้องตรวจสอบให้แน่ใจว่าตัวแปรสภาพแวดล้อมทั้งหมดของแอปพลิเคชัน Auth0 ได้รับการกำหนดค่าและตั้งค่าอย่างเหมาะสม ขั้นตอนนี้จำเป็นในการเริ่มต้นผู้ให้บริการ OAuth2 ได้สำเร็จ

เกี่ยวกับ โฟลว์

นี่คือสิ่งที่จะเกิดขึ้นเมื่อผู้ใช้ตรวจสอบสิทธิ์กับแอปพลิเคชัน:

  1. ผู้ใช้คลิกที่ปุ่มเข้าสู่ระบบบน UI ส่วนหน้า
  2. ส่วนหน้าเปลี่ยนเส้นทางผู้ใช้ไปยังปลายทาง /login ใน Backend for Frontend (BFF)
  3. BFF จะเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าเข้าสู่ระบบสากลของ Auth0 เพิ่มเติม
  4. ผู้ใช้ให้ข้อมูลประจำตัวและความยินยอมต่อกระบวนการตรวจสอบสิทธิ์
  5. หลังจากการตรวจสอบสิทธิ์สำเร็จ คำขอโทรกลับจะถูกส่งกลับไปยังปลายทาง /callback ในแอปพลิเคชัน
  6. ตัวจัดการการเรียกกลับตรวจสอบพารามิเตอร์สถานะที่ได้รับ เพื่อให้มั่นใจในความสมบูรณ์และความปลอดภัย
  7. ตัวจัดการการเรียกกลับจะแลกเปลี่ยนรหัสอนุญาตที่ได้รับสำหรับโทเค็นการเข้าถึงผ่านช่องทางที่ปลอดภัย
  8. โทเค็นการเข้าถึงที่ได้รับได้รับการตรวจสอบแล้ว
  9. โทเค็นการเข้าถึงและข้อมูลโปรไฟล์ที่เกี่ยวข้องจะถูกแยกและแคชไว้ในเซิร์ฟเวอร์ Redis
  10. ตัวจัดการจะเปลี่ยนเส้นทางผู้ใช้กลับไปที่ UI ส่วนหน้า พร้อมด้วยคุกกี้ HTTP เท่านั้น
  11. เมื่อผู้ใช้ทำการเรียก API แบ็กเอนด์จากฟรอนต์เอนด์ในภายหลัง คุกกี้จะรวมอยู่ในคำขอ
  12. คุกกี้ได้รับการตรวจสอบโดยตัวจัดการมิดเดิลแวร์ ซึ่งจะตรวจสอบสถานะการเข้าสู่ระบบของผู้ใช้ และตรวจสอบความพร้อมใช้งานของข้อมูลโปรไฟล์ในแคช
  13. ตัวจัดการ API แบ็กเอนด์จัดการโฟลว์ แยกโทเค็นการเข้าถึง JWT ออกจากแคช และเพิ่มลงในส่วนหัวการอนุญาตของคำขอที่ส่งต่อ
  14. จากนั้นคำขอจะถูกส่งต่อไปยัง API แบ็กเอนด์
  15. เมื่อได้รับการตอบสนองจากส่วนหลัง ก็จะถูกส่งต่อกลับไปยังส่วนหน้า

บทสรุป

โดยสรุป รูปแบบการตรวจสอบสิทธิ์ Backend for Frontend (BFF) ใน Go มอบแนวทางที่มีประสิทธิภาพและยืดหยุ่นในการสร้างระบบการตรวจสอบสิทธิ์สำหรับแอปพลิเคชันส่วนหน้า ด้วยการแยกข้อกังวลในการรับรองความถูกต้องออกเป็นบริการแบ็คเอนด์เฉพาะที่ปรับให้เหมาะกับไคลเอนต์ส่วนหน้าแต่ละราย นักพัฒนาสามารถสร้างระบบการรับรองความถูกต้องที่แข็งแกร่ง ปรับขนาดได้ และปลอดภัย ซึ่งตรงตามข้อกำหนดเฉพาะของแอปพลิเคชันของตน

ฉันหวังว่าบล็อกเทคโนโลยีนี้จะให้ข้อมูลเชิงลึกอันมีค่าและคำแนะนำเชิงปฏิบัติสำหรับการใช้รูปแบบการตรวจสอบสิทธิ์ BFF ใน Go ขอให้สนุกกับการเขียนโค้ด!

ซอร์สโค้ดของตัวอย่างนี้มีอยู่ที่ mehulgohil/go-bffauth