현대 인터넷 아키텍처에서 API 게이트웨이는 중요한 구성 요소가 되었으며 기업 및 클라우드 컴퓨팅 시나리오에서 널리 사용됩니다. API 게이트웨이의 주요 기능은 여러 마이크로서비스 시스템의 API 인터페이스를 균일하게 관리 및 배포하고 액세스 제어 및 보안 보호를 제공하며 API 문서 관리, 모니터링 및 로깅도 수행할 수 있습니다.
API 게이트웨이의 보안과 확장성을 더 잘 보장하기 위해 일부 액세스 제어, 인증 및 권한 부여 메커니즘도 API 게이트웨이에 추가되었습니다. 이러한 메커니즘은 사용자와 서비스 간의 합법성을 보장하고 공격과 불법적인 운영을 방지할 수 있습니다.
이 글에서는 Gin 프레임워크를 사용하여 API 게이트웨이와 인증 및 권한 부여 기능을 구현하는 방법을 소개합니다.
1. Gin 프레임워크 소개
Gin은 Go 언어를 기반으로 개발된 경량 웹 프레임워크입니다. 디자인 목표는 단순성과 사용 편의성을 유지하면서 고성능 웹 프레임워크를 제공하는 것입니다. Gin 프레임워크는 라우팅, 미들웨어, 템플릿 및 렌더링과 같은 일반적인 웹 기능을 제공하며 사용자 정의 미들웨어 및 HTTP 오류 처리 방법도 지원하므로 요구 사항에 맞는 웹 애플리케이션을 빠르게 만들 수 있습니다.
2. API 게이트웨이의 기본 프레임워크 구축
먼저 기본 웹 애플리케이션을 생성하려면 Gin 프레임워크를 설치하고 가져와야 합니다. 그 전에 로컬 환경에 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!" }
3. 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 프레임워크의 그룹 방법을 사용하여 다양한 서비스의 경로를 그룹화하고 /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"}
4. 인증 및 승인 구현
API 게이트웨이의 보안과 확장성을 보장하기 위해, 또한 인증 및 권한 부여 메커니즘을 추가해야 합니다. 여기서는 JWT(JSON Web Token)를 사용하여 인증 및 권한 부여 기능을 구현할 수 있습니다. JWT는 웹 표준을 기반으로 하는 경량 인증 및 권한 부여 방법입니다. JWT 인증 과정은 다음과 같습니다.
JWT 사용을 지원하려면 다음 라이브러리도 설치해야 합니다.
go get -u github.com/dgrijalva/jwt-go
다음으로 JWT 클레임 구조를 정의하고 UserID 및 Expiry 정보와 같은 몇 가지 필수 매개변수를 추가해야 합니다. 여기서 UserID는 사용자의 고유 ID를 기록하는 데 사용되고 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 알고리즘을 사용하여 클레임에 서명하고 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!