91 lines
2.1 KiB
Go
91 lines
2.1 KiB
Go
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
|
|
}
|