Files
go_blog/pkg/jwt/auth.go
2025-06-09 17:59:19 +08:00

91 lines
2.4 KiB
Go
Raw 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 jwt
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"go_blog/models"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
// 定义 JWT 密钥(从配置文件读取)
// var jwtSecret = []byte(config.GetJWTSecret())
var jwtSecret = []byte("your-hardcoded-secret-key")
// CustomClaims 自定义 JWT 载荷(包含用户 ID
type CustomClaims struct {
UserID uint `json:"user_id"`
jwt.RegisteredClaims
}
// GenerateToken 生成 JWT 令牌
func GenerateToken(user *models.Account) (string, error) {
expiresAt := jwt.NewNumericDate(time.Now().Add(24 * time.Hour)) // 令牌有效期 24 小时
claims := CustomClaims{
UserID: uint(user.ID),
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expiresAt,
Issuer: "go_blog",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
// VerifyToken 验证 JWT 令牌并返回用户信息
func VerifyToken(tokenStr string) (*models.Account, error) { // 修改返回类型为 *models.Account
token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return models.GetAccountByID(claims.UserID) // 假设 models 包新增 GetAccountByID 方法
}
return nil, errors.New("invalid token")
}
// AuthRequired Gin 中间件:验证 JWT 令牌
func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
// 从请求头获取 Authorization 字段格式Bearer <token>
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "请提供认证令牌"})
c.Abort()
return
}
// 解析令牌
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "令牌格式错误(应为 Bearer <token>"})
c.Abort()
return
}
// 验证令牌并获取用户
user, err := VerifyToken(parts[1])
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效或过期的令牌: " + err.Error()})
c.Abort()
return
}
// 将用户信息存入上下文(后续路由可通过 c.Get("user") 获取)
c.Set("user", user)
c.Next()
}
}