BeiBaiNian opened a new pull request, #191: URL: https://github.com/apache/casbin-gateway/pull/191
This PR is part of issue #179 "make a UI-first LLM API security gateway". Token management (milestone 1.3) is the core of the "security guardrails" selling point: it issues client-facing virtual keys (sk-xxx), enforces authentication, per-model permissions and rate limiting on the 1.2 unified endpoint /v1/chat/completions, and repays the plaintext-storage tech debt of Channel.ApiKey left over from 1.1 (AES encryption + one-time migration). # What changed - Added controllers/token.go: 5 CRUD APIs — GET /api/get-tokens (paginated), GET /api/get-token, POST /api/add-token, POST /api/update-token, POST /api/delete-token. On creation, the secret key is bcrypt-hashed; the plaintext key is returned exactly once in the creation response. List/detail responses only expose the SecretKeyPrefix mask — the key itself never leaves the DB. - Added object/token.go: Token model (owner+name composite primary key, following the object/site.go multi-tenant pattern) with SecretKeyHash (bcrypt), SecretKeyPrefix, ExpireTime (RFC3339, empty = never expires), AllowedModels ([]string, JSON-serialized, empty = allow all), RateLimit (int, 0 = unlimited), Status. GetTokenBySecretKeyHash() compares bcrypt hashes across enabled tokens. - Added object/aes.go: EncryptApiKey/DecryptApiKey (AES-256-GCM, key from env/config). Channel.ApiKey and Token.SecretKey serve different purposes: the former must be forwarded in plaintext → reversible encryption; the latter is only compared → hash-only storage. - Modified object/channel.go: AddChannel/UpdateChannel AES-encrypt the API key before writing; TestChannelConnectivity and GetChannelByModel decrypt on read; added MigrateChannelApiKeys(), an idempotent migration (attempt decryption to detect plaintext, encrypt in place if needed) invoked from InitConfig after table creation, so keys written by 1.1 are upgraded without breaking the forwarding path the moment 1.3 merges. - Added object/rate_limit.go: CheckRateLimit in-memory limiter (sync.Map, fixed one-minute windows, lazy cleanup of stale entries; limit <= 0 disables limiting). - Modified controllers/proxy.go: ChatCompletions now runs authenticateToken first — extract Authorization: Bearer → GetTokenBySecretKeyHash bcrypt compare → check Status/ExpireTime/AllowedModels/RateLimit, returning 401 (missing/invalid token), 403 (disabled/expired/model not allowed) or 429 (rate limited) as appropriate. - Modified routers/router.go: registered the 5 /api/token routes. - Modified object/ormer.go: createTable() registers Sync2(new(Token)); InitConfig calls MigrateChannelApiKeys(). - Frontend (same PR): added TokenListPage.js (list + creation modal: custom name, AllowedModels selectable from the union of existing channels' models, one-time plaintext key display with a one-click copy button), TokenEditPage.js (edit name/model permissions/rate limit/expire time/status; expire time stored as RFC3339 to match the backend time.Parse); backend/TokenBackend.js; menu routes in App.js; en/zh locale entries under the token namespace. # Verification - go vet ./... passed (fixed the call-site error caused by the TestChannelConnectivity signature change). - yarn run build passed. - Local UI testing: creating a token (custom name + model selection) works, the one-time key modal displays and the copy button works; the edit page's Expire Time now saves and re-displays correctly (fixed the DatePicker value always null and the non-RFC3339 dateString defects); list page styling aligns with ChannelListPage (pagination/loading/status tags/tooltips). - End-to-end auth chain (curl 401/403/429 states, AES migration DB verification) is deferred to the 1.6 integration milestone. # Note - This PR branches off the 1.2 branch (feat-proxy-1.2) and depends on it being merged; ship back-to-back with 1.2. - After 1.3 merges, /v1/chat/completions switches from unauthenticated to mandatory Bearer token auth — an intentional behavior change. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
