首頁  >  文章  >  後端開發  >  使用Gin框架實現API網關和認證授權功能

使用Gin框架實現API網關和認證授權功能

WBOY
WBOY原創
2023-06-22 08:57:132146瀏覽

在現代化網路架構中,API網關已經成為了重要的組成部分,被廣泛應用於企業和雲端運算的場景中。 API網關的主要功能是統一管理和分發多個微服務系統的API接口,提供存取控制和安全保護,同時也能夠進行API文件管理、監控和日誌記錄等方面的工作。

為了更能保障API網關的安全性和可擴充性,一些存取控制和認證授權的機制也加入了API網關。這樣的機制可以確保使用者和服務之間的合法性,防止攻擊和非法操作。

在本文中,我們將介紹如何使用Gin框架來實作API閘道和認證授權功能。

一、Gin框架介紹

Gin是一個輕量級的Web框架,基於Go語言開發。它的設計目標是提供高效能的Web框架,同時又保持簡單易用的特性。 Gin框架提供了路由、中間件、模板和渲染等常見的Web功能,還支援自訂中間件和HTTP錯誤處理方式,可以快速建立符合要求的網路應用程式。

二、建立API網關基礎框架

首先,我們需要安裝並匯入Gin框架,建立一個基本的Web應用程式。在此之前,我們需要在本機環境中安裝Go語言,然後執行以下命令安裝Gin框架。

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!" }

三、API網關的實作

接著,我們將對API網關進行實作。在實現API網關之前,我們需要確定哪些服務將會被納入API網關當中。這裡,我們假設我們有一個使用者管理系統、一個商品管理系統和一個訂單管理系統,同時這三個系統都有自己的API介面。

為了將這三個系統的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/ 返回{"data": "User Service API"}
http://localhost:8080/product-service/ 返回{"data" : "Product Service API"}
http://localhost:8080/order-service/ 返回{"data": "Order Service API"}

四、認證授權的實作

為了確保API網關的安全性和可擴充性,我們還需要增加認證授權的機制。在這裡,我們可以使用JWT(JSON Web Token)來實現認證和授權功能。 JWT是一種基於Web標準的輕量級身分驗證和授權方法。 JWT認證流程如下所示。

  1. 使用者要求API網關,攜帶身分資訊(例如使用者名稱和密碼等)。
  2. API網關使用身分資訊向認證伺服器發送請求,取得JWT令牌。
  3. API閘道將JWT令牌附加在請求頭或其他位置,轉送到服務端進行介面存取。
  4. 服務端根據JWT令牌進行介面訪問,自動完成認證和授權操作。

我們還需要安裝以下程式庫來支援JWT的使用。

go get -u github.com/dgrijalva/jwt-go

接著,我們需要定義一個JWT的Claims結構體,並且加入一些必要的參數,例如UserID和Expiry等資訊。這裡UserID用來記錄使用者唯一的識別標識,Expiry用來記錄令牌的有效期限。

type CustomClaims struct {
    UserID string `json:"userID,omitempty"`
    jwt.StandardClaims
}

接下來,我們將實作三個函數,generateToken、verifyToken和authMiddleware。 generateToken函數用於產生JWT令牌,具體實作如下。

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結構體的實例,將userID作為Claims的參數,同時指定了過期時間和發布者資訊Issuer。然後,我們使用HS256演算法對Claims進行簽名,呼叫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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn