package utils import ( "encoding/base64" "encoding/json" "fmt" "time" "github.com/golang-jwt/jwt/v4" ) // JWKS (JSON Web Key Set) 结构 type JWKSKey struct { Kty string `json:"kty"` Use string `json:"use"` Kid string `json:"kid"` N string `json:"n,omitempty"` E string `json:"e,omitempty"` K string `json:"k,omitempty"` // 对称密钥 Alg string `json:"alg"` } type JWKS struct { Keys []JWKSKey `json:"keys"` } // GenerateJWKSFromSecret 从密钥生成 JWKS(用于对称加密 HS256) func GenerateJWKSFromSecret(secretKey string, keyID string) *JWKS { // 对于 HS256,将密钥进行 base64 编码 encodedSecret := base64.RawURLEncoding.EncodeToString([]byte(secretKey)) return &JWKS{ Keys: []JWKSKey{ { Kty: "oct", Use: "sig", Kid: keyID, K: encodedSecret, Alg: "HS256", }, }, } } // GenerateJWKSEndpoint 生成可以被 Envoy 使用的 JWKS JSON // 此端点应在 user-rpc 中暴露,URL 为 /.well-known/jwks.json func GenerateJWKSEndpoint(secretKey string, keyID string) (string, error) { if secretKey == "" { return "", fmt.Errorf("secret key cannot be empty") } jwks := GenerateJWKSFromSecret(secretKey, keyID) jsonData, err := json.MarshalIndent(jwks, "", " ") if err != nil { return "", err } return string(jsonData), nil } // TokenPayload 令牌负载 type TokenMetadata struct { IssuedAt time.Time ExpiresAt time.Time Subject string // userId Issuer string Audience string } // ExtractTokenMetadata 从 token 中提取元数据(不验证签名) func ExtractTokenMetadata(tokenString string) (*TokenMetadata, error) { token, _, err := new(jwt.Parser).ParseUnverified(tokenString, &Claims{}) if err != nil { return nil, err } claims, ok := token.Claims.(*Claims) if !ok { return nil, fmt.Errorf("invalid token claims type") } return &TokenMetadata{ IssuedAt: claims.IssuedAt.Time, ExpiresAt: claims.ExpiresAt.Time, Subject: claims.UserId, Issuer: claims.Issuer, Audience: "", // 如果需要,可以增加到 Claims 中 }, nil }