一文详解如何在Golang中实现JWT认证与授权

 更新时间:2025年03月10日 09:39:31   作者:qq_18665023  
在现代Web应用中,安全性是一个非常重要的课题,JWT作为一种常用的认证与授权机制,已被广泛应用于各种系统中,下面我们就来看看如何在Golang中实现JWT认证与授权吧

在现代Web应用中,安全性是一个非常重要的课题。JWT(JSON Web Token)作为一种常用的认证与授权机制,已被广泛应用于各种系统中。它的优势在于轻量级、跨平台,并且非常适合分布式系统。在本文中,我们将通过Golang实现JWT认证与授权,帮助你构建更安全的API。

什么是JWT?

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境间以一个简短的字符串安全地传输信息。JWT通常用于用户认证和授权,它由三个部分组成:

1.头部(Header):通常包含两部分信息,类型(JWT)和签名算法(如HMAC SHA256或RSA)。

2.有效载荷(Payload):包含我们要传递的数据,通常是用户的身份信息或权限等。

3.签名(Signature):确保消息的完整性和防止篡改。它是通过头部和有效载荷用私钥签名生成的。

JWT的结构如下:

header.payload.signature

为什么选择JWT?

无状态性:JWT是自包含的,因此不需要存储会话信息,适合分布式系统。

跨平台:JWT的结构标准化,几乎所有语言都可以生成和解析JWT。

灵活性:可以将任意信息存储在JWT中,如用户ID、权限、过期时间等。

在Golang中实现JWT认证与授权

1. 安装所需的库

我们将使用github.com/dgrijalva/jwt-go库来生成和验证JWT。首先,使用go get安装该库:

go get github.com/dgrijalva/jwt-go

2. 创建JWT生成与解析功能

我们将创建一个简单的JWT生成和验证模块,允许用户通过用户名和密码登录,并获取一个JWT进行后续请求。

生成JWT

在auth.go文件中,编写JWT生成函数:

package main
 
import (
    "github.com/dgrijalva/jwt-go"
    "time"
    "log"
)
 
// 密钥用于签名和验证JWT
var jwtKey = []byte("secret")
 
// 用户信息结构体
type Claims struct {
    Username string `json:"username"`
    jwt.StandardClaims
}
 
// 生成JWT
func GenerateJWT(username string) (string, error) {
    expirationTime := time.Now().Add(1 * time.Hour) // 设置JWT过期时间为1小时
    claims := &Claims{
        Username: username,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expirationTime.Unix(),
        },
    }
 
    // 创建一个新的JWT对象,使用HMAC SHA256算法签名
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 
    // 使用密钥签名并返回生成的JWT字符串
    return token.SignedString(jwtKey)
}

解析JWT

然后,编写JWT解析函数,验证其有效性并提取用户信息:

// 解析JWT并返回用户名
func ParseJWT(tokenStr string) (string, error) {
    claims := &Claims{}
    token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
        // 返回签名时使用的密钥
        return jwtKey, nil
    })
 
    if err != nil {
        return "", err
    }
 
    if !token.Valid {
        return "", err
    }
 
    return claims.Username, nil
}

3. 实现登录接口

接下来,我们实现一个登录接口,用户可以通过提供用户名和密码来获取JWT。

package main
 
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
 
// 假设的用户数据,实际应用中应使用数据库
var users = map[string]string{
    "user1": "password1",
    "user2": "password2",
}
 
func main() {
    r := gin.Default()
 
    // 登录接口
    r.POST("/login", func(c *gin.Context) {
        var loginData map[string]string
        if err := c.ShouldBindJSON(&loginData); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
            return
        }
 
        username, password := loginData["username"], loginData["password"]
 
        // 验证用户名和密码
        if correctPassword, exists := users[username]; exists && correctPassword == password {
            // 生成JWT
            token, err := GenerateJWT(username)
            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
                return
            }
 
            c.JSON(http.StatusOK, gin.H{"token": token})
        } else {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
        }
    })
 
    r.Run(":8080")
}

4. 实现受保护的路由

为了保护需要授权的路由,我们需要编写中间件来验证JWT。只有通过验证的请求才能访问这些路由。

// JWT验证中间件
func JWTMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取Authorization头部
        tokenStr := c.GetHeader("Authorization")
        if tokenStr == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing token"})
            c.Abort()
            return
        }
 
        // 解析JWT并获取用户名
        username, err := ParseJWT(tokenStr)
        if err != nil {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            c.Abort()
            return
        }
 
        // 将用户名添加到上下文中,以便后续使用
        c.Set("username", username)
        c.Next()
    }
}
 
func main() {
    r := gin.Default()
 
    // 登录接口
    r.POST("/login", func(c *gin.Context) {
        var loginData map[string]string
        if err := c.ShouldBindJSON(&loginData); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
            return
        }
 
        username, password := loginData["username"], loginData["password"]
 
        if correctPassword, exists := users[username]; exists && correctPassword == password {
            token, err := GenerateJWT(username)
            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
                return
            }
 
            c.JSON(http.StatusOK, gin.H{"token": token})
        } else {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
        }
    })
 
    // 受保护的路由,必须通过JWT验证
    authorized := r.Group("/protected")
    authorized.Use(JWTMiddleware())
    authorized.GET("/hello", func(c *gin.Context) {
        username := c.MustGet("username").(string)
        c.JSON(http.StatusOK, gin.H{
            "message": "Hello, " + username,
        })
    })
 
    r.Run(":8080")
}

5. 测试JWT认证

##16bWaaVUGAdS8d39CilS9PXEtEptU809NqHfKBuiVYk=##

首先,通过/login接口获取JWT:

curl -X POST http://localhost:8080/login -H "Content-Type: application/json" -d '{"username":"user1", "password":"password1"}'

返回结果:

{ "token": "your-jwt-token" }

然后,使用返回的JWT访问受保护的路由:

curl -X GET http://localhost:8080/protected/hello -H "Authorization: your-jwt-token"

返回结果:

{ "message": "Hello, user1" }

结语

通过本文的讲解,你应该已经掌握了如何在Golang中使用JWT进行认证与授权。JWT凭借其无状态性和跨平台的特点,成为了分布式系统中实现认证与授权的理想选择。你可以将这个基本的认证系统进一步扩展,如支持权限控制、刷新令牌等功能。

以上就是一文详解如何在Golang中实现JWT认证与授权的详细内容,更多关于Golang JWT认证与授权的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言实现二进制与十进制互转的示例代码

    Go语言实现二进制与十进制互转的示例代码

    这篇文章主要和大家详细介绍了Go语言中实现二进制与十进制互相转换的示例代码,文中的代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-05
  • 基于微服务框架go-micro开发gRPC应用程序

    基于微服务框架go-micro开发gRPC应用程序

    这篇文章介绍了基于微服务框架go-micro开发gRPC应用程序的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Go语言生成UUID的利器(github.com/google/uuid)

    Go语言生成UUID的利器(github.com/google/uuid)

    UUID是确保每个元素唯一性的重要工具,Go语言虽然在标准库中没有直接提供UUID生成功能,但可以通过安装github.com/google/uuid库来实现,本文就来介绍一下,感兴趣的可以了解一下
    2024-11-11
  • go语言题解LeetCode1160拼写单词示例详解

    go语言题解LeetCode1160拼写单词示例详解

    这篇文章主要为大家介绍了go语言题解LeetCode1160拼写单词示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Go语言HttpRouter路由使用方法详解

    Go语言HttpRouter路由使用方法详解

    这篇文章主要介绍了Go语言HttpRouter路由使用方法详解,需要的朋友可以参考下
    2022-04-04
  • Go语言中服务网格Istio实战

    Go语言中服务网格Istio实战

    本文主要介绍了Go语言中服务网格Istio实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-04-04
  • 如何使用Golang打包jar应用

    如何使用Golang打包jar应用

    go:embed 是 Go 1.16 引入的一个强大功能,它允许在编译时将外部文件或目录嵌入到 Go 程序中,下面介绍如何使用 go:embed 来嵌入JAR 文件,感兴趣的朋友一起看看吧
    2025-04-04
  • Go实现分布式唯一ID的生成之雪花算法

    Go实现分布式唯一ID的生成之雪花算法

    本文主要介绍了Go实现分布式唯一ID的生成之雪花算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 一文带你了解Go语言中函数设计的实践示例

    一文带你了解Go语言中函数设计的实践示例

    良好设计的函数具有清晰的职责和逻辑结构,提供准确的命名和适当的参数控制,下面我们将一一描述函数设计时能够遵循的最佳实践,希望对大家有所帮助
    2023-06-06
  • 使用Golang打印特定的日期时间的操作

    使用Golang打印特定的日期时间的操作

    这篇文章主要给大家详细介绍了如何使用Golang打印特定的日期时间的操作,文中有详细的代码示例,具有一定的参考价值,需要的朋友可以参考下
    2023-07-07

最新评论