93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package utils
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/golang-jwt/jwt/v5"
|
||
|
|
"golang.org/x/crypto/bcrypt"
|
||
|
|
)
|
||
|
|
|
||
|
|
// JWTClaims JWT声明结构体
|
||
|
|
type JWTClaims struct {
|
||
|
|
UserID uint `json:"user_id"`
|
||
|
|
Username string `json:"username"`
|
||
|
|
IsAdmin bool `json:"is_admin"`
|
||
|
|
jwt.RegisteredClaims
|
||
|
|
}
|
||
|
|
|
||
|
|
// GenerateToken 生成JWT令牌
|
||
|
|
func GenerateToken(userID uint, username string, isAdmin bool, secretKey string, expireTime time.Duration) (string, error) {
|
||
|
|
// 创建声明
|
||
|
|
claims := JWTClaims{
|
||
|
|
UserID: userID,
|
||
|
|
Username: username,
|
||
|
|
IsAdmin: isAdmin,
|
||
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
||
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireTime)),
|
||
|
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
|
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建令牌
|
||
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||
|
|
|
||
|
|
// 签名令牌
|
||
|
|
tokenString, err := token.SignedString([]byte(secretKey))
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return tokenString, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ParseToken 解析JWT令牌
|
||
|
|
func ParseToken(tokenString string, secretKey string) (*JWTClaims, error) {
|
||
|
|
// 解析令牌
|
||
|
|
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, 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 []byte(secretKey), nil
|
||
|
|
})
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
// 验证令牌并获取声明
|
||
|
|
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
||
|
|
return claims, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil, fmt.Errorf("invalid token")
|
||
|
|
}
|
||
|
|
|
||
|
|
// HashPassword 密码加密
|
||
|
|
func HashPassword(password string) (string, error) {
|
||
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return string(hash), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// VerifyPassword 密码验证
|
||
|
|
func VerifyPassword(hashedPassword, password string) error {
|
||
|
|
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
|
||
|
|
}
|
||
|
|
|
||
|
|
// GenerateRandomString 生成随机字符串
|
||
|
|
func GenerateRandomString(length int) string {
|
||
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||
|
|
randomBytes := make([]byte, length)
|
||
|
|
for i := range randomBytes {
|
||
|
|
randomBytes[i] = charset[time.Now().UnixNano()%int64(len(charset))]
|
||
|
|
}
|
||
|
|
return string(randomBytes)
|
||
|
|
}
|