Phase 3-A 完整实现,包含: Gateway (lijiaoqiao/gateway): - RemoteTokenRuntime 缓存实现: active=30s/expired=2m/revoked=10m TTL淘汰 - LRU 容量淘汰 (max_entries=10000,插入顺序淘汰) - HTTPTimeoutConfig: 4个环境变量 (Dial/KeepAlive/Read/Write/MaxIdle) - 缓存命中率指标: GetCacheHitRate() + 实例级别统计 - 上游延迟指标: RecordTokenRuntime() histogram - buildTimeoutClient: 基于 HTTPTimeoutConfig 的 HTTP 客户端工厂 - 新增测试: 22个矩阵测试 (remote_runtime_matrix_test.go, config_test.go) Platform Token Runtime (lijiaoqiao/platform-token-runtime): - metrics/metrics.go: GetCacheHitRate() 方法 - inmemory_runtime.go: GetCacheHitRate() 实现 变更文件 (8 modified + 5 new): - gateway/internal/middleware/remote_runtime.go # 核心缓存实现 - gateway/internal/middleware/remote_runtime_test.go - gateway/internal/middleware/remote_runtime_cache_test.go - gateway/internal/middleware/remote_runtime_matrix_test.go - gateway/internal/middleware/remote_runtime_metrics_test.go - gateway/internal/metrics/metrics.go # 新增 - gateway/internal/config/config.go # HTTPTimeoutConfig - gateway/internal/config/config_test.go - gateway/internal/app/bootstrap.go # 初始化顺序 - gateway/internal/router/router.go # 指标注入 - platform-token-runtime/internal/metrics/metrics.go # 新增 - platform-token-runtime/internal/app/bootstrap.go - platform-token-runtime/internal/auth/service/inmemory_runtime.go
76 lines
1.9 KiB
Go
76 lines
1.9 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRemoteTokenRuntime_VerifyAndResolve(t *testing.T) {
|
|
httpClient := &http.Client{
|
|
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
if req.URL.Path != "/api/v1/platform/tokens/introspect" {
|
|
return &http.Response{
|
|
StatusCode: http.StatusNotFound,
|
|
Body: io.NopCloser(strings.NewReader("not found")),
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}
|
|
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(strings.NewReader(`{
|
|
"request_id":"req-1",
|
|
"data":{
|
|
"token_id":"tok-1",
|
|
"subject_id":"user-1",
|
|
"role":"org_admin",
|
|
"status":"active",
|
|
"scope":["gateway:invoke"],
|
|
"issued_at":"2026-04-10T10:00:00Z",
|
|
"expires_at":"2026-04-10T11:00:00Z"
|
|
}
|
|
}`)),
|
|
Header: make(http.Header),
|
|
}, nil
|
|
}),
|
|
}
|
|
|
|
runtime := NewRemoteTokenRuntime("http://token-runtime.internal", httpClient, func() time.Time {
|
|
return time.Date(2026, 4, 10, 10, 30, 0, 0, time.UTC)
|
|
})
|
|
|
|
claims, err := runtime.Verify(context.Background(), "raw-token")
|
|
if err != nil {
|
|
t.Fatalf("Verify returned error: %v", err)
|
|
}
|
|
if claims.TokenID != "tok-1" {
|
|
t.Fatalf("expected token id tok-1, got %s", claims.TokenID)
|
|
}
|
|
|
|
status, err := runtime.Resolve(context.Background(), claims.TokenID)
|
|
if err != nil {
|
|
t.Fatalf("Resolve returned error: %v", err)
|
|
}
|
|
if status != TokenStatusActive {
|
|
t.Fatalf("expected active status, got %s", status)
|
|
}
|
|
}
|
|
|
|
type roundTripFunc func(req *http.Request) (*http.Response, error)
|
|
|
|
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return f(req)
|
|
}
|
|
|
|
func jsonResp(status int, body string) *http.Response {
|
|
return &http.Response{
|
|
StatusCode: status,
|
|
Body: io.NopCloser(strings.NewReader(body)),
|
|
Header: make(http.Header),
|
|
}
|
|
}
|