102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
// JWT Token 生成与解析 + 业务工具函数
|
||
package utils
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/golang-jwt/jwt/v5"
|
||
)
|
||
|
||
// JWTClaims JWT 载荷,包含用户 ID 和角色列表
|
||
type JWTClaims struct {
|
||
UserID uint `json:"user_id"`
|
||
RoleCode string `json:"role_code"` // 角色(visitor/employee/guard)
|
||
jwt.RegisteredClaims
|
||
}
|
||
|
||
// AdminJWTClaims 管理员 JWT 载荷
|
||
type AdminJWTClaims struct {
|
||
AdminID uint `json:"admin_id"`
|
||
Account string `json:"account"`
|
||
jwt.RegisteredClaims
|
||
}
|
||
|
||
// GenerateAdminToken 生成管理员 JWT
|
||
func GenerateAdminToken(adminID uint, account string, secret string, expireHours int) (string, error) {
|
||
claims := AdminJWTClaims{
|
||
AdminID: adminID,
|
||
Account: account,
|
||
RegisteredClaims: jwt.RegisteredClaims{
|
||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)),
|
||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
Issuer: "lktx-admin",
|
||
},
|
||
}
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||
return token.SignedString([]byte(secret))
|
||
}
|
||
|
||
// ParseAdminToken 解析管理员 JWT
|
||
func ParseAdminToken(tokenString string, secret string) (*AdminJWTClaims, error) {
|
||
token, err := jwt.ParseWithClaims(tokenString, &AdminJWTClaims{}, 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(secret), nil
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if claims, ok := token.Claims.(*AdminJWTClaims); ok && token.Valid {
|
||
return claims, nil
|
||
}
|
||
return nil, fmt.Errorf("invalid token")
|
||
}
|
||
|
||
// GenerateToken 生成 JWT(单角色,兼容旧版)
|
||
func GenerateToken(userID uint, roleCode string, secret string, expireHours int) (string, error) {
|
||
claims := JWTClaims{
|
||
UserID: userID,
|
||
RoleCode: roleCode,
|
||
RegisteredClaims: jwt.RegisteredClaims{
|
||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)),
|
||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
Issuer: "lktx-mp",
|
||
},
|
||
}
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||
return token.SignedString([]byte(secret))
|
||
}
|
||
|
||
// ParseToken 解析并验证 JWT
|
||
func ParseToken(tokenString string, secret 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(secret), 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")
|
||
}
|
||
|
||
// GenerateInviteCode 生成 16 位随机邀请码
|
||
func GenerateInviteCode() string {
|
||
b := make([]byte, 8)
|
||
rand.Read(b)
|
||
return hex.EncodeToString(b)
|
||
}
|
||
|
||
// GenerateQRCodeContent 生成二维码内容
|
||
func GenerateQRCodeContent(appointmentID uint) string {
|
||
return fmt.Sprintf("LKTX:APPT:%d:%d", appointmentID, time.Now().Unix())
|
||
}
|