Files
2026-07-10 10:06:47 +00:00

84 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
// 上下文键名常量,用于在 gin.Context 中存取鉴权后的用户信息
const (
ContextUserID = "user_id"
ContextRole = "role"
)
// Claims JWT 自定义声明结构,嵌入标准声明
type Claims struct {
UserID uint `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
// JWTAuth JWT 鉴权中间件,校验 Bearer Token 并将用户信息写入上下文
func JWTAuth(secret string) gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "message": "缺少认证信息", "data": nil})
c.Abort()
return
}
// 提取 Bearer <token> 中的 token 部分
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "message": "认证格式错误", "data": nil})
c.Abort()
return
}
tokenString := strings.TrimSpace(parts[1])
// 解析并校验 token,同时确认签名算法为 HMAC
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrTokenSignatureInvalid
}
return []byte(secret), nil
})
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "message": "无效或过期的令牌", "data": nil})
c.Abort()
return
}
// 鉴权成功,将用户信息写入上下文供后续 handler 使用
c.Set(ContextUserID, claims.UserID)
c.Set(ContextRole, claims.Role)
c.Next()
}
}
// GetUserID 从上下文获取用户 ID,未取到时返回 0
func GetUserID(c *gin.Context) uint {
if v, exists := c.Get(ContextUserID); exists {
if uid, ok := v.(uint); ok {
return uid
}
}
return 0
}
// GetRole 从上下文获取用户角色,未取到时返回空字符串
func GetRole(c *gin.Context) string {
if v, exists := c.Get(ContextRole); exists {
if role, ok := v.(string); ok {
return role
}
}
return ""
}