Files
shangbangbang/pkg/utils/jwtUtil.go
T
solosw 99b11b04e4 1.0
2026-01-05 14:11:34 +08:00

192 lines
4.5 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 jwtutil
import (
"awesomeProject/internal/common"
"errors"
"fmt"
"reflect"
"time"
"github.com/golang-jwt/jwt/v5"
)
// getSecretKey 获取密钥
func getSecretKey() []byte {
if common.MineConfig != nil {
return []byte(common.MineConfig.JWT.SecretKey)
}
// 默认密钥(仅开发环境使用)
return []byte("your-very-secret-key-32-bytes")
}
// getTokenExpireDuration 获取Token过期时间
func getTokenExpireDuration() time.Duration {
if common.MineConfig != nil {
return time.Duration(common.MineConfig.JWT.ExpireHours) * time.Hour
}
// 默认24小时
return time.Hour * 24
}
// 通用:生成 Token,支持任意结构体
func GenerateToken(claims interface{}) (string, error) {
// 1. 将结构体转换为 map[string]interface{}
claimMap, err := structToMap(claims)
if err != nil {
return "", err
}
// 2. 添加标准声明(exp, iat, nbf
claimMap["exp"] = time.Now().Add(getTokenExpireDuration()).Unix()
claimMap["iat"] = time.Now().Unix()
claimMap["nbf"] = time.Now().Unix()
// 3. 创建 Token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claimMap))
// 4. 签名
return token.SignedString(getSecretKey())
}
func ParseTokenToMap(tokenString string) (map[string]interface{}, error) {
token, err := jwt.Parse(tokenString, 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 getSecretKey(), nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("token is invalid")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, errors.New("token claims is invalid")
}
return claims, nil
}
func ParseToken(tokenString string, dest interface{}) error {
if reflect.TypeOf(dest).Kind() != reflect.Ptr {
return errors.New("dest must be a pointer to a struct")
}
token, err := jwt.Parse(tokenString, 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 getSecretKey(), nil
})
if err != nil {
return err
}
if !token.Valid {
return errors.New("token 无效")
}
// 提取 MapClaims
if claims, ok := token.Claims.(jwt.MapClaims); ok {
// 将 MapClaims 转回结构体
if err := mapToStruct(claims, dest); err != nil {
return err
}
return nil
}
return errors.New("无法解析 token 声明")
}
// 将结构体转为 map[string]interface{}
func structToMap(obj interface{}) (map[string]interface{}, error) {
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return nil, errors.New("输入必须是结构体")
}
result := make(map[string]interface{})
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
jsonTag := fieldType.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
continue
}
key := jsonTag
result[key] = field.Interface()
}
return result, nil
}
// 将 map[string]interface{} 转回结构体
func mapToStruct(data map[string]interface{}, dest interface{}) error {
val := reflect.ValueOf(dest)
if val.Kind() != reflect.Ptr {
return errors.New("dest 必须是指针")
}
val = val.Elem()
if val.Kind() != reflect.Struct {
return errors.New("dest 必须是指针指向结构体")
}
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := val.Type().Field(i)
jsonTag := fieldType.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
continue
}
if field.CanSet() {
value, ok := data[jsonTag]
if !ok {
continue
}
// 自动类型转换
switch field.Kind() {
case reflect.String:
if s, ok := value.(string); ok {
field.SetString(s)
}
case reflect.Int, reflect.Int64:
if n, ok := value.(float64); ok {
field.SetInt(int64(n))
}
case reflect.Uint, reflect.Uint64:
if n, ok := value.(float64); ok {
field.SetUint(uint64(n))
}
case reflect.Bool:
if b, ok := value.(bool); ok {
field.SetBool(b)
}
case reflect.Float64:
if f, ok := value.(float64); ok {
field.SetFloat(f)
}
default:
continue
}
}
}
return nil
}
func ValidateToken(tokenString string, dest interface{}) bool {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return getSecretKey(), nil
})
return err == nil && token.Valid && ParseToken(tokenString, dest) == nil
}