Dalam seni bina Internet moden, get laluan API telah menjadi komponen penting dan digunakan secara meluas dalam senario perusahaan dan pengkomputeran awan. Fungsi utama gerbang API adalah untuk mengurus dan mengedarkan antara muka API berbilang sistem mikro perkhidmatan secara seragam, menyediakan kawalan akses dan perlindungan keselamatan, dan juga boleh melaksanakan pengurusan, pemantauan dan pengelogan dokumen API.
Untuk memastikan keselamatan dan kebolehskalaan get laluan API dengan lebih baik, beberapa kawalan akses dan mekanisme pengesahan dan kebenaran juga telah ditambahkan pada get laluan API. Mekanisme sedemikian boleh memastikan kesahihan antara pengguna dan perkhidmatan dan mencegah serangan dan operasi haram.
Dalam artikel ini, kami akan memperkenalkan cara menggunakan rangka kerja Gin untuk melaksanakan gerbang API dan fungsi pengesahan dan kebenaran.
1. Pengenalan kepada rangka kerja Gin
Gin ialah rangka kerja web ringan yang dibangunkan berdasarkan bahasa Go. Matlamat reka bentuknya adalah untuk menyediakan rangka kerja web berprestasi tinggi sambil mengekalkan kesederhanaan dan kemudahan penggunaan. Rangka kerja Gin menyediakan fungsi web biasa seperti penghalaan, perisian tengah, templat dan pemaparan Ia juga menyokong kaedah pengendalian ralat middleware dan HTTP, membolehkan anda membuat aplikasi web dengan cepat yang memenuhi keperluan anda.
2. Bina rangka kerja asas get laluan API
Pertama, kita perlu memasang dan mengimport rangka kerja Gin untuk mencipta aplikasi web asas. Sebelum ini, kita perlu memasang bahasa Go dalam persekitaran setempat, dan kemudian laksanakan arahan berikut untuk memasang rangka kerja Gin.
go get -u github.com/gin-gonic/gin
Seterusnya, kami mencipta fail main.go sebagai fail kemasukan program.
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") }
Dalam kod di atas, kami mengimport pustaka rangka kerja Gin dan mencipta laluan lalai. Laluan akar laluan ("/") boleh mengembalikan maklumat respons format JSON untuk sebarang kaedah permintaan (Mana-mana). Akhirnya, kami memulakan perkhidmatan HTTP melalui kaedah Run dan mendengar port tempatan 8080.
Sekarang, kita boleh memasukkan arahan berikut dalam terminal untuk memulakan program dan mengesahkan sama ada ia boleh berfungsi seperti biasa.
go run main.go
Jika semuanya baik-baik saja, anda sepatutnya boleh mengakses http://localhost:8080/ dalam penyemak imbas atau klien lain dan melihat respons berikut dalam format JSON.
{ "message": "Hello, Gin!" }
3. Pelaksanaan API Gateway
Seterusnya, kami akan melaksanakan API Gateway. Sebelum melaksanakan get laluan API, kita perlu menentukan perkhidmatan mana yang akan disertakan dalam get laluan API. Di sini, kami menganggap bahawa kami mempunyai sistem pengurusan pengguna, sistem pengurusan produk dan sistem pengurusan pesanan, dan ketiga-tiga sistem ini mempunyai antara muka API mereka sendiri.
Untuk menggabungkan antara muka API ketiga-tiga sistem ini ke dalam get laluan API, kami perlu mengumpulkan dan memajukan laluan. Cara yang lebih mudah ialah mengumpulkan perkhidmatan mikro yang berbeza mengikut fungsi mereka Sebagai contoh, penghalaan boleh ditakrifkan seperti ini.
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") }
Dalam contoh kod di atas, kami menggunakan kaedah Kumpulan rangka kerja Gin untuk mengumpulkan laluan perkhidmatan yang berbeza dan meletakkannya dalam /perkhidmatan-pengguna, /perkhidmatan-produk dan /perkhidmatan-pesanan di bawah a laluan. Kemudian, kami menambah laluan untuk perkhidmatan yang berbeza dan masing-masing menentukan maklumat tindak balas yang berbeza Di sini, hanya rentetan ringkas dikembalikan.
Jika anda melancarkan program sekarang dan mengakses setiap perkhidmatan, anda seharusnya melihat maklumat berikut.
http://localhost:8080/user-service/ mengembalikan {"data": "API Perkhidmatan Pengguna"}
http://localhost:8080/product-service/ mengembalikan {"data" : "API Perkhidmatan Produk"}
http://localhost:8080/order-service/ Kembalikan {"data": "API Perkhidmatan Pesanan"}
4. Pelaksanaan pengesahan dan kebenaran
Untuk memastikan keselamatan dan kebolehskalaan get laluan API, kami juga perlu menambah mekanisme pengesahan dan kebenaran. Di sini, kita boleh menggunakan JWT (JSON Web Token) untuk melaksanakan fungsi pengesahan dan kebenaran. JWT ialah kaedah pengesahan dan kebenaran ringan berdasarkan piawaian web. Proses pengesahan JWT adalah seperti berikut.
Kami juga perlu memasang perpustakaan berikut untuk menyokong penggunaan JWT.
go get -u github.com/dgrijalva/jwt-go
Seterusnya, kita perlu mentakrifkan struktur Tuntutan JWT dan menambah beberapa parameter yang diperlukan, seperti UserID dan maklumat Tamat tempoh. Di sini UserID digunakan untuk merekodkan identiti unik pengguna, dan Expiry digunakan untuk merekodkan tempoh sah token.
type CustomClaims struct { UserID string `json:"userID,omitempty"` jwt.StandardClaims }
Seterusnya, kami akan melaksanakan tiga fungsi, generateToken, verifyToken dan authMiddleware. Fungsi generateToken digunakan untuk menjana token JWT Pelaksanaan khusus adalah seperti berikut.
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) }
Dalam kod di atas, kami mencipta contoh struktur Tuntutan Tersuai, menggunakan ID pengguna sebagai parameter Tuntutan dan menentukan masa tamat tempoh dan Pengeluar maklumat penerbit. Kemudian, kami menggunakan algoritma HS256 untuk menandatangani Tuntutan, memanggil kaedah SignedString untuk menjana token JWT dan mengembalikannya kepada pelanggan.
Seterusnya, kami akan melaksanakan fungsi verifyToken untuk mengesahkan token.
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令牌。
Atas ialah kandungan terperinci Gunakan rangka kerja Gin untuk melaksanakan gerbang API dan fungsi pengesahan dan kebenaran. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!