package auth import ( "context" "fmt" "strings" jwt "github.com/golang-jwt/jwt/v5" ) type contextKey string const userContextKey contextKey = "gateway_user_id" // Verifier 负责在 gateway 入口层校验用户 JWT。 type Verifier struct { secret []byte } // NewVerifier 初始化入口 JWT 校验器。 func NewVerifier(secret string) *Verifier { return &Verifier{secret: []byte(secret)} } // VerifyUserID 只负责从 Authorization header 中提取并校验用户身份。 // HTTP 状态码和响应 envelope 属于 transport 层,auth 包不直接写 ResponseWriter。 func (v *Verifier) VerifyUserID(header string) (int64, error) { if !strings.HasPrefix(header, "Bearer ") { return 0, fmt.Errorf("missing bearer token") } tokenString := strings.TrimPrefix(header, "Bearer ") token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) { if token.Method.Alg() != jwt.SigningMethodHS256.Alg() { return nil, fmt.Errorf("unexpected signing method") } return v.secret, nil }) if err != nil || !token.Valid { return 0, fmt.Errorf("invalid token") } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return 0, fmt.Errorf("invalid claims") } rawUserID, ok := claims["user_id"].(float64) if !ok { return 0, fmt.Errorf("missing user_id") } return int64(rawUserID), nil } // WithUserID 把已鉴权用户写入请求上下文,供 gateway 组装 RequestMeta。 func WithUserID(ctx context.Context, userID int64) context.Context { return context.WithValue(ctx, userContextKey, userID) } // UserIDFromContext 提取鉴权后的用户 ID。 func UserIDFromContext(ctx context.Context) int64 { userID, _ := ctx.Value(userContextKey).(int64) return userID }