在現代化網路架構中,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認證流程如下所示。
我們還需要安裝以下程式庫來支援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中文網其他相關文章!