1.0
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user