gin框架jwt认证

middlewares/authmiddleware.go

// 导入必要的包
package middlewares

import (
	"net/http" // HTTP 状态码和常量
	"time"     // 时间操作,用于设置 token 过期时间

	"github.com/gin-gonic/gin"     // Web 框架
	"github.com/golang-jwt/jwt/v5" // JWT 库
)

// 定义 JWT 签名密钥(生产环境应使用环境变量)
var jwtSecret = []byte("qweasdzxc")

// 自定义 JWT 声明结构体
type Claims struct {
	Username             string `json:"username"` // 用户名,将存储在 token 中
	jwt.RegisteredClaims        // 嵌入标准声明(过期时间、发布时间等)
}

// 生成 JWT token 的函数
func GenerateToken(username string) (string, error) {
	// 创建声明对象
	claims := Claims{
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 设置过期时间:24小时后
			IssuedAt:  jwt.NewNumericDate(time.Now()),                     // 设置发布时间:当前时间
		},
	}

	// 使用 HS256 算法和声明创建 token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用密钥签名并返回 token 字符串
	return token.SignedString(jwtSecret)
}

// 认证中间件函数
func AuthMiddleware() gin.HandlerFunc {
	// 返回一个 gin.HandlerFunc(中间件函数)
	return func(c *gin.Context) {
		// 从请求头中获取 Authorization 字段
		tokenString := c.GetHeader("Authorization")
		// 如果 token 为空,返回 401 未授权错误
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少授权 token"})
			c.Abort() // 终止请求处理
			return
		}

		// 移除 "Bearer " 前缀(如果存在)
		if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
			tokenString = tokenString[7:] // 截取第 7 个字符之后的部分
		}

		// 解析并验证 token
		token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
			return jwtSecret, nil // 返回密钥用于验证签名
		})

		// 如果解析出错或 token 无效,返回 401 错误
		if err != nil || !token.Valid {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的 token"})
			c.Abort() // 终止请求
			return
		}

		// 尝试将 token 的声明转换为 Claims 类型
		if claims, ok := token.Claims.(*Claims); ok {
			// 将用户名存入上下文,供后续处理器使用
			c.Set("username", claims.Username)
			c.Next() // 继续处理下一个中间件或处理器
		} else {
			// 类型转换失败,返回错误
			c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的 token claims"})
			c.Abort() // 终止请求
		}
	}
}

main.go

package main

import (
	"fmt"
	"gojwt/middlewares"
	"gojwt/routers"
	"net/http"

	"log"

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

func FaultError(err error, error string) {
	if err != nil {
		log.Printf("%s: %v", error, err)
	}
}

func initMiddleware(ctx *gin.Context) {
	fmt.Println("我是一个中间件")
	ctx.Next()
}

func main() {
	r := gin.Default()
	r.Use(initMiddleware)
	// r.Use(middlewares.AuthMiddleware())
	routers.ApiRouterInit(r)

	r.GET("/", middlewares.AuthMiddleware(), func(ctx *gin.Context) {
		value, _ := ctx.Get("username")
		ctx.JSON(200, gin.H{
			"message": "ok",
			"user":    value,
		})
	})
	r.POST("/login", func(c *gin.Context) {
		// 定义匿名结构体接收 JSON 数据
		var credentials struct {
			Username string `json:"username"`
			Password string `json:"password"`
		}
		// 绑定 JSON 数据到结构体
		if err := c.BindJSON(&credentials); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		// 验证凭证(实际项目中应查询数据库)
		if credentials.Username == "admin" && credentials.Password == "password" {
			// 验证成功,生成 token(忽略错误)
			token, _ := middlewares.GenerateToken(credentials.Username)
			// 返回 token 给客户端
			c.JSON(http.StatusOK, gin.H{"token": token})
		} else {
			// 验证失败,返回 401 错误
			c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的凭证"})
		}
	})
	r.Run()
}

posted @ 2025-12-30 16:25  shuix1ng  阅读(0)  评论(0)    收藏  举报