>백엔드 개발 >Golang >Gin 프레임워크를 사용하여 API 게이트웨이와 인증 및 권한 부여 기능 구현

Gin 프레임워크를 사용하여 API 게이트웨이와 인증 및 권한 부여 기능 구현

WBOY
WBOY원래의
2023-06-22 08:57:132231검색

현대 인터넷 아키텍처에서 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 인증 과정은 다음과 같습니다.

  1. 사용자는 ID 정보(사용자 이름, 비밀번호 등)를 전달하는 API 게이트웨이를 요청합니다.
  2. API 게이트웨이는 ID 정보를 사용하여 인증 서버에 요청을 보내고 JWT 토큰을 얻습니다.
  3. API 게이트웨이는 JWT 토큰을 요청 헤더 또는 기타 위치에 첨부하고 인터페이스 액세스를 위해 서버로 전달합니다.
  4. 서버는 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.