使用JWT身份验证构建Golang API
#编程 #go #jwt #learning

首先,让我们从一些背景信息开始。 JWT代表JSON Web令牌,它是将各方之间的信息安全传输为JSON对象的标准。 JWT通常用于身份验证和授权目的,它们由三个部分组成:标头,有效载荷和签名。

当用户登录到您的应用程序时,您可以生成JWT并将其发送回客户端。然后,客户端可以将JWT包括在对您的API的后续请求中,您的API可以使用JWT来验证用户并授权访问受保护的资源。

现在,让我们研究代码。首先,我们使用GIN框架创建基本的Golang API。确保在继续之前安装了杜松子酒:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    router.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, world!",
        })
    })

    router.Run(":8080")
}

此代码创建了一个简单的API,该API在端口8080上听,并以“ Hello,World!”做出响应。当您向根端点提出get请求时。

接下来,我们将在API中添加JWT身份验证。我们将使用github.com/dgrijalva/jwt-go软件包来生成和验证JWTS。

package main

import (
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

var jwtKey = []byte("my_secret_key")

func main() {
    router := gin.Default()

    router.POST("/login", login)

    auth := router.Group("/auth")
    auth.Use(authMiddleware())
    {
        auth.GET("/hello", hello)
    }

    router.Run(":8080")
}

func login(c *gin.Context) {
    var loginData struct {
        Username string `json:"username" binding:"required"`
        Password string `json:"password" binding:"required"`
    }

    if err := c.ShouldBindJSON(&loginData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    if loginData.Username != "myuser" || loginData.Password != "mypassword" {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid login credentials"})
        return
    }

    expirationTime := time.Now().Add(5 * time.Minute)
    claims := &jwt.StandardClaims{
        ExpiresAt: expirationTime.Unix(),
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    tokenString, err := token.SignedString(jwtKey)

    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
        return
    }

    c.JSON(http.StatusOK, gin.H{"token": tokenString})
}

func authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenString := c.GetHeader("Authorization")
        if tokenString == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
            return
        }

        token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, jwt.ErrInvalidSigningMethod
            }

            return jwtKey, nil
        })

        if err != nil {
            if err == jwt.ErrSignatureInvalid {
                c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"})
                return
            }

            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            return
        }

        if !token.Valid {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            return
        }

        c.Next()
    }
}

func hello(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"message": "Hello, authenticated user!"})
}

让我们逐步浏览此代码。首先,我们定义一个将用于签名和验证JWT的jwtKey变量。该键应保密,而不是与任何人共享。

接下来,我们定义两个端点:/login/auth/hello/login端点以JSON格式接受用户名和密码,检查它们是否有效,并在JWT中生成JWT。 /auth/hello端点需要在请求的Authorization标题中包含有效的JWT。

login函数首先检查用户名和密码是否有效。如果是的话,它将创建一个新的JWT,其到期时间为5分钟,并以JSON格式返回客户。

authMiddleware函数是一个中间件,可以检查请求的Authorization标头中是否包含有效的JWT。如果存在有效的JWT,它将调用c.Next()以允许请求继续进行。如果不存在有效的JWT或无效,则返回错误响应。

最后,hello函数是一个受保护的端点,需要访问有效的JWT。如果存在有效的JWT,它将返回“您好,身份验证的用户!” json格式的消息。

让我们开始讨论我们用来在Golang API中实现JWT身份验证的jwt-go软件包。该软件包提供了用于创建,解析和验证JWT的功能。

创建JWT时,我们首先创建一个StandardClaims结构,该结构包括我们要在JWT有效载荷中包含的任何主张,例如到期时间。然后,我们使用jwt.NewWithClaims函数创建一个新的JWT,并使用我们的jwtKey变量签名。然后,随后的签名JWT包含在对客户端的响应中。

验证JWT时,我们首先从请求的Authorization标头中提取JWT,然后使用jwt.ParseWithClaims函数解析。我们将jwtKey变量作为第二个参数传递给此函数,以验证JWT的签名。如果JWT有效并且尚未过期,我们致电c.Next()以允许请求继续。如果JWT无效或已过期,我们返回错误响应。

重要的是要注意,应与HTTPS结合使用JWT,以确保它们安全地传输。 JWT也应保密,而不是与其他任何人共享。

除了jwt-go软件包外,我们还使用了Gin框架来创建Golang API。 Gin是一个轻巧的Web框架,可提供诸如路由,中间件和错误处理之类的功能。我们在API:/login中定义了两个端点,如果用户提供有效的凭据,它将生成JWT,而/auth/hello(需要有效的JWT)。

就是这样! 使用此代码,您创建了一个具有JWT身份验证的Golang API。当然,您可以自定义此代码以满足您的特定需求,但这应该给您一个很好的起点。