Heim  >  Artikel  >  Backend-Entwicklung  >  Golang implementiert die SSO-Anmeldung

Golang implementiert die SSO-Anmeldung

PHPz
PHPzOriginal
2023-05-10 11:33:361222Durchsuche

Mit der Entwicklung des Internets müssen immer mehr Websites und Anwendungen die Single-Sign-On-Funktionalität (SSO) implementieren, um ein besseres Benutzererlebnis und höhere Sicherheit zu bieten. In diesem Artikel stellen wir vor, wie Sie die SSO-Anmeldung mithilfe der Go-Sprache implementieren.

1. Was ist SSO?

Single Sign-On (SSO) ist ein Authentifizierungsprotokoll, das es Benutzern ermöglicht, mit einem einzigen Benutzernamen und Passwort auf mehrere Anwendungen zuzugreifen, anstatt sich für jede Anwendung einzeln zu authentifizieren. In einem SSO-System müssen Benutzer nur bei der ersten Anmeldung Anmeldeinformationen angeben und werden bei nachfolgenden Anmeldungen automatisch angemeldet.

Das Kernprinzip von SSO besteht darin, Anmeldeinformationen zwischen verschiedenen Domänen zu teilen. In diesem Fall müssen die Anmeldeinformationen des Benutzers (z. B. Benutzername und Passwort) nur in einer Domäne überprüft werden und können dann für den Zugriff auf Anwendungen in anderen Domänen verwendet werden. Dieser Prozess kann den Anmeldevorgang des Benutzers vereinfachen, die Belastung des Benutzers verringern und die Sicherheit verbessern.

2. Wie implementiert man SSO?

Um die SSO-Anmeldung zu implementieren, müssen wir ein öffentliches Authentifizierungszentrum (Authentifizierungszentrum) definieren, das mit jeder Anwendung kommuniziert. Die Authentifizierungsstelle ist dafür verantwortlich, die Anmeldeinformationen des Benutzers zu validieren und dann jeder Anwendung ein Token bereitzustellen, damit der Benutzer auf die Anwendung zugreifen kann. Bei späteren Besuchen kann sich der Benutzer mithilfe des Tokens authentifizieren, ohne erneut Anmeldeinformationen angeben zu müssen.

In der Go-Sprache können wir das leichte Web-Framework Gin verwenden, um die SSO-Anmeldung zu implementieren. Unten ist eine grundlegende SSO-Architektur:

SSO Architecture

Im obigen Bild haben wir ein Zertifizierungszentrum und zwei Anwendungen (App1 und App2) definiert, SSO-Anmeldung werden zwischen ihnen durch die Zertifizierungsstelle umgesetzt. Wir verwenden JWT (JSON Web Token) zur Darstellung von Token, da es sich um einen einfachen Standard handelt, der JSON zum Beschreiben und Übertragen von Informationen verwenden kann.

3. Wie erreicht man das?

  1. GIN installieren

Zuerst müssen wir das Gin-Framework installieren. Geben Sie den folgenden Befehl auf dem Terminal ein, um Gin zu installieren:

go get -u github.com/gin-gonic/gin
  1. Zertifizierungsstelle schreiben

Als nächstes müssen wir den Code für schreiben Zertifizierungsstelle. In diesem Beispiel verwenden wir das Gin-Framework, um einen HTTP-Server zu erstellen. Wir müssen den Benutzer am Server anmelden und ein JWT-Token erstellen, um den Benutzer darzustellen. Das Token wird nach der Authentifizierung an den Benutzer zurückgegeben und bei nachfolgenden Anfragen überprüft.

package main

import (
  "net/http"
  "time"

  "github.com/gin-gonic/gin"
  "github.com/golang-jwt/jwt"
)

var jwtKey = []byte("my_secret_key")

type Credentials struct {
  Username string `json:"username"`
  Password string `json:"password"`
}

type Claims struct {
  Username string `json:"username"`
  jwt.StandardClaims
}

func main() {
  router := gin.Default()

  router.POST("/login", loginHandler)

  router.GET("/validate", validateHandler)

  router.Run(":8080")
}

func loginHandler(c *gin.Context) {
  var creds Credentials
  if err := c.BindJSON(&creds); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
    return
  }

  if creds.Username != "user" || creds.Password != "password" {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
    return
  }

  expirationTime := time.Now().Add(5 * time.Minute)
  claims := &Claims{
    Username: creds.Username,
    StandardClaims: jwt.StandardClaims{
      ExpiresAt: expirationTime.Unix(),
    },
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  tokenString, err := token.SignedString(jwtKey)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
    return
  }

  c.JSON(http.StatusOK, gin.H{"token": tokenString})
}

func validateHandler(c *gin.Context) {
  tokenString := c.Request.Header.Get("Authorization")
  if tokenString == "" {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
    return
  }

  token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, jwt.ErrSignatureInvalid
    }
    return jwtKey, nil
  })

  if err != nil {
    c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
    return
  }

  if !token.Valid {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
    return
  }

  claims, ok := token.Claims.(*Claims)
  if !ok {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Failed to parse claims"})
    return
  }

  c.JSON(http.StatusOK, gin.H{"username": claims.Username})
}

Im Zertifizierungszentrum definieren wir zwei Routen „/login“ und „/validate“.

Auf der Route „/login“ lesen wir die Anmeldeinformationen und validieren sie (hier nur ein einfaches Beispiel). Wenn die Validierung erfolgreich ist, erstellen wir ein JWT-Token und senden es an den Client zurück.

Auf der Route „/validate“ lesen wir das JWT-Token und validieren es mit demselben geheimen Schlüssel. Wenn der Token gültig ist, extrahieren wir die darin enthaltenen Ansprüche und senden sie an den Kunden zurück.

  1. Anwendung schreiben

Als nächstes müssen wir den Code für die Anwendung schreiben. In diesem Beispiel verwenden wir das Gin-Framework, um einen HTTP-Server zu erstellen. Wir müssen auf die Authentifizierungsstelle zugreifen, um die Anmeldeinformationen des Benutzers zu überprüfen und nach der Überprüfung das JWT-Token zu erhalten. Das Token wird in einem Cookie gespeichert und bei nachfolgenden Anfragen überprüft.

package main

import (
  "net/http"

  "github.com/gin-gonic/gin"
  "github.com/golang-jwt/jwt"
)

var jwtKey = []byte("my_secret_key")

type Claims struct {
  Username string `json:"username"`
  jwt.StandardClaims
}

func main() {
  router := gin.Default()

  router.POST("/login", loginHandler)

  router.GET("/private", authMiddleware(), privateHandler)

  router.Run(":8081")
}

func loginHandler(c *gin.Context) {
  username := c.PostForm("username")
  password := c.PostForm("password")

  authURL := "http://localhost:8080/validate"
  client := &http.Client{}
  req, err := http.NewRequest("GET", authURL, nil)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"})
    return
  }

  req.Header.Set("Authorization", c.GetHeader("Authorization"))
  res, err := client.Do(req)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to validate token"})
    return
  }

  if res.StatusCode != http.StatusOK {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
    return
  }

  claims := &Claims{
    Username: username,
    StandardClaims: jwt.StandardClaims{},
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  tokenString, err := token.SignedString(jwtKey)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
    return
  }

  c.SetCookie("token", tokenString, 0, "", "", false, true)
  c.JSON(http.StatusOK, gin.H{"message": "Login success"})
}

func privateHandler(c *gin.Context) {
  claims := c.MustGet("claims").(*Claims)
  c.JSON(http.StatusOK, gin.H{"message": "You are logged in as " + claims.Username})
}

func authMiddleware() gin.HandlerFunc {
  return func(c *gin.Context) {
    tokenString, err := c.Cookie("token")
    if err != nil {
      c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication required"})
      c.Abort()
      return
    }

    token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
      if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
        return nil, jwt.ErrSignatureInvalid
      }
      return jwtKey, nil
    })

    if err != nil {
      c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
      c.Abort()
      return
    }

    if !token.Valid {
      c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
      c.Abort()
      return
    }

    claims, ok := token.Claims.(*Claims)
    if !ok {
      c.JSON(http.StatusUnauthorized, gin.H{"error": "Failed to parse claims"})
      c.Abort()
      return
    }

    c.Set("claims", claims)
    c.Next()
  }
}

In der Anwendung haben wir zwei Routen „/login“ und „/private“ definiert.

Auf der Route „/login“ stellen wir eine GET-Anfrage an die Authentifizierungsstelle und fügen das JWT-Token zur Überprüfung in den Anfrageheader ein. Wenn die Überprüfung erfolgreich ist, erstellen wir ein JWT-Token und speichern es in einem Cookie.

Auf der Route „/private“ verwenden wir Middleware, um zu überprüfen, ob das JWT-Token in der Anfrage enthalten ist. Wenn der Token gültig ist, extrahieren wir die darin enthaltenen Ansprüche und verarbeiten sie entsprechend.

4. Zusammenfassung

In diesem Artikel haben wir vorgestellt, wie man die Go-Sprache verwendet, um die Single-Sign-On-Funktion (SSO) zu implementieren. Wir haben das Gin-Framework zum Erstellen des HTTP-Servers verwendet und JWT-Tokens zur Darstellung von Benutzern verwendet. Wir definieren eine Zertifizierungsstelle und nutzen diese, um Anfragen zu validieren und Token auszustellen. Wir haben auch die Anwendung codiert und Middleware zur Authentifizierung verwendet. Dieses Beispiel ist nur ein einfaches Beispiel und kann erweitert werden, um spezifische Anwendungsanforderungen zu erfüllen.

Das obige ist der detaillierte Inhalt vonGolang implementiert die SSO-Anmeldung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn