news 2026/4/18 8:41:30

go jwt

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
go jwt

我来为你详细介绍在 Go 语言中使用 JWT 的实践方案。

Go 语言 JWT 库推荐

Go 生态中最流行的 JWT 库是 `github.com/golang-jwt/jwt/v5`(原 `dgrijalva/jwt-go` 的社区维护分支,更安全可靠)。

快速开始

1. 安装依赖

```bash
go get github.com/golang-jwt/jwt/v5
```

2. 基础使用示例

生成 Token(登录时)

```go
package main

import (
"time"
"github.com/golang-jwt/jwt/v5"
)

// 定义密钥(生产环境应从环境变量读取)
var jwtSecret = []byte("your-256-bit-secret")

// 自定义 Claims 结构
type UserClaims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims // 内嵌标准声明
}

// 生成 JWT
func GenerateToken(userID uint, username string) (string, error) {
claims := UserClaims{
UserID: userID,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 24小时过期
IssuedAt: jwt.NewNumericDate(time.Now()),
Subject: "user_token",
},
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
```

解析和验证 Token(中间件中)

```go
// 解析 JWT
func ParseToken(tokenString string) (*UserClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
// 验证签名算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrSignatureInvalid
}
return jwtSecret, nil
})

if err != nil {
return nil, err
}

if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
return claims, nil
}
return nil, jwt.ErrInvalidKey
}
```

Gin 框架集成示例

这是实际项目中最常见的使用场景:

```go
package main

import (
"net/http"
"strings"
"time"

"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)

var jwtSecret = []byte("your-secret-key")

// JWT 中间件
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证头"})
c.Abort()
return
}

// 提取 Bearer token
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
c.JSON(http.StatusUnauthorized, gin.H{"error": "认证头格式错误"})
c.Abort()
return
}

// 解析 token
claims, err := ParseToken(parts[1])
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的token"})
c.Abort()
return
}

// 将用户信息存入上下文
c.Set("userID", claims.UserID)
c.Set("username", claims.Username)
c.Next()
}
}

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

// 公开路由
r.POST("/login", loginHandler)

// 需要认证的路由组
api := r.Group("/api")
api.Use(JWTAuthMiddleware())
{
api.GET("/profile", profileHandler)
api.POST("/logout", logoutHandler)
}

r.Run(":8080")
}

// 登录处理
func loginHandler(c *gin.Context) {
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}

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

// 验证用户名密码(示例,实际应查数据库)
if req.Username != "admin" || req.Password != "123456" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "认证失败"})
return
}

// 生成 token
token, err := GenerateToken(1, req.Username)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"})
return
}

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

// 获取个人信息(需要认证)
func profileHandler(c *gin.Context) {
userID, _ := c.Get("userID")
username, _ := c.Get("username")

c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": username,
})
}
```

高级特性

使用 RSA 非对称加密(更安全的微服务场景)

```go
// 生成 Token(使用私钥)
func GenerateTokenWithRSA(userID uint, privateKey *rsa.PrivateKey) (string, error) {
claims := jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}

token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
return token.SignedString(privateKey)
}

// 验证 Token(使用公钥)
func ParseTokenWithRSA(tokenString string, publicKey *rsa.PublicKey) (*jwt.Token, error) {
return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return publicKey, nil
})
}
```

Token 刷新机制

```go
// RefreshToken 在 token 即将过期时生成新 token
func RefreshToken(tokenString string) (string, error) {
claims, err := ParseToken(tokenString)
if err != nil {
return "", err
}

// 检查是否需要刷新(例如剩余时间小于30分钟)
if time.Until(claims.ExpiresAt.Time) > 30*time.Minute {
return "", errors.New("token 尚未需要刷新")
}

// 生成新 token
return GenerateToken(claims.UserID, claims.Username)
}
```

目录结构建议

```
project/
├── internal/
│ ├── middleware/
│ │ └── jwt.go # JWT 中间件
│ └── utils/
│ └── jwt.go # JWT 工具函数
├── pkg/
│ └── config/
│ └── config.go # 密钥配置
└── cmd/
└── server/
└── main.go
```

安全最佳实践

实践 说明
密钥管理 使用环境变量或密钥管理服务(KMS),不要硬编码
算法选择 优先使用 `HS256` 或 `RS256`,避免 `none` 算法
过期时间 设置合理的过期时间(建议 15分钟-2小时)
HTTPS 传输 生产环境必须使用 HTTPS
Token 存储 前端存储在 `httpOnly` Cookie 或内存中,避免 LocalStorage XSS 风险

需要了解更具体的场景实现(如 Redis 存储黑名单实现登出、多设备登录控制等)吗?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 17:27:14

‌大模型测试脚本生成器:基于GPT-5的跨语言自动化代码转换工具‌

AI驱动测试脚本生成的新纪元 2026年,AI与自动化测试工具在公众号内容中热度占比超40%,阅读量平均提升35%,成为软件测试领域的核心焦点。这一趋势源于生成式AI工具的崛起,如基于大模型的测试脚本生成器,能显著减少手动…

作者头像 李华
网站建设 2026/4/18 0:38:09

基于Springboot+Vue的少数民族传统服饰销售商城平台设计与实现

前言 🌞博主介绍:✌CSDN特邀作者、全栈领域优质创作者、10年IT从业经验、码云/掘金/知乎/B站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战,以及程序定制化开发、文档编写、答疑辅导等。✌…

作者头像 李华
网站建设 2026/4/18 0:44:33

‌AI战争伦理:自主武器系统决策链的沙盒测试环境‌

AI战争伦理与测试的紧迫性 人工智能(AI)在军事领域的应用正重塑战争形态,自主武器系统通过减少人为干预提升效率,但决策链的加速可能引发误判或伦理失控。例如,AI系统在复杂战场中可能未充分评估后果就做出攻击指令&a…

作者头像 李华