インターネットの発展に伴い、より優れたユーザー エクスペリエンスとより高いセキュリティを提供するために、シングル サインオン (SSO) 機能を実装する必要がある Web サイトやアプリケーションがますます増えています。今回はGo言語を使ったSSOログインの実装方法を紹介します。
1.SSO とは何ですか?
シングル サインオン (SSO) は、ユーザーがアプリケーションごとに個別に認証するのではなく、単一のユーザー名とパスワードを使用して複数のアプリケーションにアクセスできるようにする認証プロトコルです。 SSO システムでは、ユーザーは初回ログイン時にのみ資格情報を入力する必要があり、それ以降のログインでは自動的にログインされます。
SSO の中心原則は、異なるドメイン間で資格情報を共有することです。この場合、ユーザーの資格情報 (ユーザー名やパスワードなど) は 1 つのドメインで検証するだけで済み、その後、その資格情報を使用して他のドメインのアプリケーションにアクセスできます。この処理により、ユーザーのログイン処理が簡素化され、ユーザーの負担が軽減され、セキュリティが向上します。
2. SSO を実装するにはどうすればよいですか?
SSO ログインを実装するには、各アプリケーションと通信する公的認証センター (Authentication Center) を定義する必要があります。認証局は、ユーザーの資格情報を検証し、ユーザーがアプリケーションにアクセスできるようにするためのトークンを各アプリケーションに提供する責任があります。次回のアクセスでは、ユーザーは資格情報を再度提供しなくても、トークンを使用して認証できます。
Go 言語では、軽量 Web フレームワーク gin を使用して SSO ログインを実装できます。基本的な SSO アーキテクチャは次のとおりです。
上の図では、認証センターと 2 つのアプリケーション (App1 と App2) を定義し、それらの間で認証されます。 SSO ログイン。 JWT (JSON Web Token) は、JSON を使用して情報を記述および送信できる軽量の標準であるため、トークンを表すために使用します。
3.それを達成するにはどうすればよいですか?
まず、Gin フレームワークをインストールする必要があります。ターミナルで次のコマンドを入力して、gin をインストールします。
go get -u github.com/gin-gonic/gin
次に、証明機関のコードを記述する必要があります。この例では、Gin フレームワークを使用して HTTP サーバーを作成します。ユーザーをサーバーにログインさせ、ユーザーを表す JWT トークンを作成する必要があります。トークンは認証後にユーザーに返され、後続のリクエストで検証されます。
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}) }
認証センターでは、「/login」と「/validate」という 2 つのルートを定義します。
「/login」ルートで、資格情報を読み取って検証し (ここでは単なる例にすぎません)、検証に合格した場合は、JWT トークンを作成してクライアントに送り返します。
「/validate」ルートで、JWT トークンを読み取り、同じ秘密キーを使用して検証します。トークンが有効な場合、トークン内のクレームを抽出してクライアントに送り返します。
次に、アプリケーションのコードを作成する必要があります。この例では、Gin フレームワークを使用して HTTP サーバーを作成します。認証局にアクセスしてユーザーの資格情報を検証し、検証後に JWT トークンを取得する必要があります。トークンは Cookie に保存され、後続のリクエストで検証されます。
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() } }
アプリケーションでは、「/login」と「/private」という 2 つのルートを定義しました。
「/login」ルートで、証明機関への GET リクエストを作成し、検証のためにリクエスト ヘッダーに JWT トークンを追加します。検証に合格すると、JWT トークンが作成され、Cookie に保存されます。
「/private」ルートでは、ミドルウェアを使用して、リクエストに JWT トークンが含まれているかどうかを確認します。トークンが有効な場合、トークン内のクレームが抽出され、それに応じて処理されます。
4. まとめ
この記事では、Go 言語を使用してシングル サインオン (SSO) 機能を実装する方法を紹介しました。 Gin フレームワークを使用して HTTP サーバーを作成し、JWT トークンを使用してユーザーを表しました。認証局を定義し、それを使用してリクエストを検証し、トークンを発行します。また、アプリケーションをコーディングし、認証にミドルウェアを使用しました。この例は単なる単純な例であり、特定のアプリケーションのニーズに合わせて拡張できます。
以上がgolang は sso ログインを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。