最新のインターネット アーキテクチャでは、API ゲートウェイは重要なコンポーネントとなっており、エンタープライズおよびクラウド コンピューティングのシナリオで広く使用されています。 API ゲートウェイの主な機能は、複数のマイクロサービス システムの API インターフェイスを均一に管理および分散し、アクセス制御とセキュリティ保護を提供することです。また、API ドキュメントの管理、監視、ロギングも実行できます。
API ゲートウェイのセキュリティとスケーラビリティをより確実に確保するために、いくつかのアクセス制御、認証および認可メカニズムも API ゲートウェイに追加されました。このような仕組みにより、ユーザーとサービス間の正当性を確保し、攻撃や不正操作を防ぐことができます。
この記事では、Gin フレームワークを使用して API ゲートウェイと認証・認可機能を実装する方法を紹介します。
1. Gin フレームワークの紹介
Gin は、Go 言語に基づいて開発された軽量の Web フレームワークです。その設計目標は、シンプルさと使いやすさを維持しながら、高性能の Web フレームワークを提供することです。 Gin フレームワークは、ルーティング、ミドルウェア、テンプレート、レンダリングなどの一般的な Web 機能を提供し、カスタム ミドルウェアや HTTP エラー処理メソッドもサポートしているため、要件を満たす Web アプリケーションを迅速に作成できます。
2. API ゲートウェイの基本フレームワークを構築する
まず、Gin フレームワークをインストールしてインポートし、基本的な Web アプリケーションを作成する必要があります。その前に、ローカル環境に Go 言語をインストールし、次のコマンドを実行して Jin フレームワークをインストールする必要があります。
go get -u github.com/gin-gonic/gin
次に、プログラムのエントリ ファイルとして main.go ファイルを作成します。
package main import "github.com/gin-gonic/gin" func main() { router := gin.Default() router.Any("/", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "Hello, Gin!", }) }) router.Run(":8080") }
上記のコードでは、Gin フレームワーク ライブラリをインポートし、デフォルト ルートを作成しました。ルートのルートパス(「/」)は、任意のリクエストメソッド(Any)に対してJSON形式の応答情報を返すことができます。最後に、Run メソッドを通じて HTTP サービスを開始し、ローカル ポート 8080 をリッスンしました。
ここで、ターミナルに次のコマンドを入力してプログラムを起動し、正常に動作するかどうかを確認します。
go run main.go
すべてがうまくいけば、ブラウザまたは他のクライアントで http://localhost:8080/ にアクセスし、JSON 形式で次の応答が表示されるはずです。
{ "message": "Hello, Gin!" }
3. API ゲートウェイの実装
次に、API ゲートウェイを実装します。 API ゲートウェイを実装する前に、API ゲートウェイにどのサービスを含めるかを決定する必要があります。ここでは、ユーザー管理システム、商品管理システム、注文管理システムがあり、これら 3 つのシステムがそれぞれ独自の API インターフェースを持っていると仮定します。
これら 3 つのシステムの API インターフェイスを API ゲートウェイに組み込むには、ルートをグループ化して転送する必要があります。より簡単な方法は、さまざまなマイクロサービスを機能に応じてグループ化することです。たとえば、ルーティングは次のように定義できます。
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.Default() userService := router.Group("/user-service") { userService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "User Service API"}) }) } productService := router.Group("/product-service") { productService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "Product Service API"}) }) } orderService := router.Group("/order-service") { orderService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "Order Service API"}) }) } router.Run(":8080") }
上記のコード例では、Gin フレームワークの Group メソッドを使用してさまざまなサービスのルートをグループ化し、それらを /user-service、/product-service、および /order-service. の下に配置しました。パス。次に、異なるサービスのルートを追加し、それぞれ異なる応答情報を指定しますが、ここでは単純な文字列のみが返されます。
今すぐプログラムを起動して各サービスにアクセスすると、次の情報が表示されるはずです。
http://localhost:8080/user-service/ returns {"data": "ユーザー サービス API"}
http://localhost:8080/product-service/ returns {"data" : "Product Service API"}
http://localhost:8080/order-service/ returns {"data": "Order Service API"}
4. 認証と認可の実装
API ゲートウェイのセキュリティとスケーラビリティを確保するには、認証と認可のメカニズムも追加する必要があります。ここでは、JWT (JSON Web Token) を使用して認証および認可機能を実装できます。 JWT は、Web 標準に基づいた軽量の認証および認可方法です。 JWT の認証プロセスは次のとおりです。
JWT の使用をサポートするには、次のライブラリもインストールする必要があります。
go get -u github.com/dgrijalva/jwt-go
次に、JWT クレーム構造を定義し、UserID や有効期限情報などの必要なパラメーターを追加する必要があります。ここで、UserID はユーザーの一意の ID を記録するために使用され、Expiry はトークンの有効期間を記録するために使用されます。
type CustomClaims struct { UserID string `json:"userID,omitempty"` jwt.StandardClaims }
次に、generateToken、verifyToken、authMiddleware の 3 つの関数を実装します。 JWTトークンの生成にはgenerateToken関数を使用し、具体的な実装は以下の通りです。
func generateToken(userID string) (string, error) { claims := CustomClaims{ userID, jwt.StandardClaims{ ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), Issuer: "my-api-gateway", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) jwtSecret := []byte("my-secret-key") return token.SignedString(jwtSecret) }
上記のコードでは、CustomClaims 構造のインスタンスを作成し、Claims のパラメーターとして userID を使用し、有効期限と発行者情報の Issuer を指定します。次に、HS256 アルゴリズムを使用してクレームに署名し、SignedString メソッドを呼び出して JWT トークンを生成し、それをクライアントに返します。
次に、トークンを検証するために verifyToken 関数を実装します。
func verifyToken(tokenString string) (*CustomClaims, error) { jwtSecret := []byte("my-secret-key") token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") }
在上面的代码中,我们首先定义了一个JWT Secret(这里我们使用字符串"my-secret-key"作为密钥),然后使用ParseWithClaims方法解析令牌,并将Claims参数设置为CustomClaims类型。然后,我们使用定义的JWT Secret对令牌进行验证,如果验证通过,我们将返回Claims结构体的实例。
最后一个函数是authMiddleware,用于检查请求头中是否携带有效的JWT令牌。如果没有携带或验证失败,中间件将会返回401错误给客户端。
func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) return } tokenString := strings.Replace(authHeader, "Bearer ", "", 1) claims, err := verifyToken(tokenString) if err != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) return } c.Set("userID", claims.UserID) c.Next() } }
在上面的代码中,我们首先从请求头中获取Authorization信息,并判断是否为空。如果为空,返回401错误。然后,我们使用strings.Replace方法将Token中的Bearer前缀进行删除,获取真正的JWT令牌。接着,我们调用verifyToken函数对JWT令牌进行验证,如果验证不通过,返回401错误。最后,我们将userID存储在Context中,以备其他中间件和路由使用。
为了演示JWT认证的功能,我们在/user-service服务中添加一个需要身份验证的路由,例如/user-service/profile,它返回用户的详细信息。修改后的main.go代码示例如下。
func main() { router := gin.Default() userService := router.Group("/user-service") { userService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "User Service API"}) }) userService.GET("/profile", authMiddleware(), func(c *gin.Context) { userID := c.MustGet("userID").(string) c.JSON(http.StatusOK, gin.H{"data": "User ID: " + userID}) }) } productService := router.Group("/product-service") { productService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "Product Service API"}) }) } orderService := router.Group("/order-service") { orderService.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"data": "Order Service API"}) }) } router.Run(":8080") }
以上代码中,我们在/user-service/profile路由中使用了authMiddleware中间件,来对身份进行验证。例如,如果你想要访问/user-service/profile接口,你需要在请求头中附带有效的JWT令牌,例如:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySURfaWQiOiIxMjM0NTY3ODkwIiwiZXhwIjoxNjMyMzMzNjE0LCJpc3MiOiJteS1hcGktZ2F0ZXdheSJ9OfXlna_Qb2giRByaev2x7w5zz0S2CJZnMMgZ6sVA
如果你尝试访问此路由,但请求头中没有附带有效的JWT令牌,或者令牌验证失败,你将会得到以下JSON格式的响应。
{ "error": "Unauthorized" }
如果你携带了有效的JWT令牌,你应该可以看到以下格式的响应。
{ "data": "User ID: 1234567890" }
五、总结
在本文中,我们介绍了如何使用Gin框架来实现API网关和认证授权功能。我们创建了一个基本的Web应用程序,并将多个微服务系统的API接口纳入到API网关当中。为了提高API网关的安全性和可扩展性,我们使用了JWT认证和授权的机制,通过设置Claims结构体参数来生成和验证JWT令牌,最后使用了AuthMiddleware来检查请求头中的JWT令牌。
以上がGin フレームワークを使用して API ゲートウェイと認証および認可機能を実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。