使用Golang Gin和JWT实现安全认证机制

在使用Golang Gin框架结合JWT实现安全认证时遇到几个问题想请教:

  1. 如何在Gin中正确配置JWT中间件进行路由保护?尝试了github上的几个库但总是报错
  2. JWT token的有效期设置多长比较合理?目前设置的24小时感觉不太安全
  3. refresh token的实现方案是否有必要?如果要实现该如何设计
  4. 存储在客户端的token应该如何防范CSRF攻击?看到有建议说用双重cookie验证但不太清楚具体实现
  5. 遇到token被盗用的情况,除了设置黑名单外还有什么更好的解决方案?
3 回复

使用Gin框架结合JWT(JSON Web Token)实现安全认证的步骤如下:

  1. 安装依赖

    go get github.com/gin-gonic/gin
    go get github.com/dgrijalva/jwt-go
    
  2. 生成JWT Token: 用户登录时,验证用户名和密码后生成Token。Token包含用户ID等信息,并通过密钥签名。

    func generateToken(userID uint) (string, error) {
        token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
            "userID": userID,
            "exp":    time.Now().Add(time.Hour * 24).Unix(), // 设置有效期
        })
        return token.SignedString([]byte("your-secret-key"))
    }
    
  3. 中间件验证Token: 在需要认证的路由中添加中间件,检查请求头中的Authorization字段。

    func authMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            tokenStr := c.GetHeader("Authorization")
            if tokenStr == "" {
                c.JSON(401, gin.H{"error": "未提供Token"})
                c.Abort()
                return
            }
            token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
                return []byte("your-secret-key"), nil
            })
            if err != nil || !token.Valid {
                c.JSON(401, gin.H{"error": "无效Token"})
                c.Abort()
                return
            }
            claims, ok := token.Claims.(jwt.MapClaims)
            if !ok {
                c.JSON(401, gin.H{"error": "无法解析Token"})
                c.Abort()
                return
            }
            userID := uint(claims["userID"].(float64))
            c.Set("userID", userID) // 将用户ID存储到上下文中
        }
    }
    
  4. 路由配置

    func main() {
        r := gin.Default()
        r.POST("/login", func(c *gin.Context) {
            var login struct{ Username, Password string }
            c.Bind(&login)
            if login.Username == "admin" && login.Password == "123456" {
                token, _ := generateToken(1)
                c.JSON(200, gin.H{"token": token})
            } else {
                c.JSON(401, gin.H{"error": "用户名或密码错误"})
            }
        })
    
        r.Use(authMiddleware())
        r.GET("/protected", func(c *gin.Context) {
            userID := c.MustGet("userID").(uint)
            c.JSON(200, gin.H{"message": "保护资源访问成功", "userID": userID})
        })
    
        r.Run(":8080")
    }
    

通过这种方式,你可以为Gin应用添加基于JWT的认证机制,确保只有携带有效Token的用户才能访问受保护的资源。

更多关于使用Golang Gin和JWT实现安全认证机制的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Gin框架结合JWT(JSON Web Token)可以快速构建一个安全的认证机制。首先安装依赖:go get github.com/gin-gonic/gingo get github.com/dgrijalva/jwt-go

  1. 生成Token:用户登录时验证用户名密码,通过后生成JWT,包含用户ID等信息,用jwt.NewWithClaims创建,并用密钥签名。

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "id": userId,
        "exp": time.Now().Add(time.Hour * 24).Unix(),
    })
    tokenString, err := token.SignedString([]byte("your-secret-key"))
    
  2. 验证Token:在每个需要保护的接口中,从请求头获取Token并解析验证。

    func authMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            tokenString := c.Request.Header.Get("Authorization")
            token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
                return []byte("your-secret-key"), nil
            })
            if err != nil || !token.Valid {
                c.JSON(401, gin.H{"error": "Invalid token"})
                c.Abort()
                return
            }
            c.Next()
        }
    }
    
  3. 路由保护:在需要认证的路由上应用authMiddleware

    r := gin.Default()
    r.POST("/login", loginHandler)
    r.GET("/protected", authMiddleware(), protectedHandler)
    

这样就实现了基本的认证机制,确保只有携带有效Token的请求能访问受保护的资源。

使用Gin和JWT实现安全认证机制

下面是一个使用Gin框架和JWT(JSON Web Token)实现安全认证的完整示例:

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"net/http"
	"time"
)

// 用户信息结构体
type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// JWT密钥
var jwtKey = []byte("my_secret_key")

// 登录处理函数
func login(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 实际应用中这里应该查询数据库验证用户
	if user.Username != "admin" || user.Password != "password" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
		return
	}

	// 创建JWT令牌
	expirationTime := time.Now().Add(24 * time.Hour)
	claims := &jwt.RegisteredClaims{
		Subject:   user.Username,
		ExpiresAt: jwt.NewNumericDate(expirationTime),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
		return
	}

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

// 验证JWT的中间件
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"})
			c.Abort()
			return
		}

		claims := &jwt.RegisteredClaims{}
		token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
			return jwtKey, nil
		})

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

		c.Set("username", claims.Subject)
		c.Next()
	}
}

// 受保护的路由
func protected(c *gin.Context) {
	username := c.MustGet("username").(string)
	c.JSON(http.StatusOK, gin.H{"message": "Welcome " + username})
}

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

	r.POST("/login", login)

	// 受保护的路由组
	protectedRoutes := r.Group("/api")
	protectedRoutes.Use(authMiddleware())
	{
		protectedRoutes.GET("/protected", protected)
	}

	r.Run(":8080")
}

关键点说明

  1. JWT生成

    • 使用jwt.NewWithClaims创建令牌
    • 设置过期时间(示例中为24小时)
    • 使用密钥签名令牌
  2. JWT验证中间件

    • 检查Authorization头
    • 解析并验证令牌
    • 提取声明信息并传递给后续处理程序
  3. 路由保护

    • 将中间件应用于需要认证的路由组
  4. 实际应用建议

    • 将密钥存储在安全位置(如环境变量)
    • 使用更复杂的用户验证逻辑
    • 考虑刷新令牌机制
    • 实施适当的错误处理

这个实现提供了基本的JWT认证功能,可根据实际需求进行扩展。

回到顶部