BeiBaiNian opened a new pull request, #195:
URL: https://github.com/apache/casbin-gateway/pull/195

   # Why
   
   The /v1/chat/completions gateway endpoint has no authentication at all: 
anyone who knows the address can burn upstream LLM quota through the configured 
channels. Following the mentor's three-tier priority (working features → user 
experience → security), this PR delivers the milestone 1.3 core: API token 
management with Bearer authentication, plus rate limiting, a model allowlist 
and expiration times. Secret keys are stored as plaintext per (the project is 
locally deployed; encryption is deferred), and that does not block this PR.
   
   # Changes
   
   Backend:
   
   - object/token.go (new): Token model and CRUD; `sk-`-prefixed 48-char random 
secret key generation; masked keys in list responses; validateToken checks 
(non-empty name/displayName, RFC3339 expire time, at most 200 allowed models 
with at most 100 chars each, status enum).
   - controllers/token.go (new): five management APIs (get-tokens paginated 
list / get-token / add-token / update-token / delete-token) with tenant 
isolation (non-admins can only operate on their own tokens).
   - object/rate_limit.go (new): per-token per-minute window rate limiting; 
entries guarded by sync.Mutex (fixes the lost count++ under concurrency of the 
first draft); stale entry cleanup throttled by a timestamp (at most one full 
sweep per minute).
   - controllers/proxy.go: authentication chain wired in (Bearer plaintext 
comparison → status → expiration fail-closed → model allowlist → rate limit); a 
malformed expiration time no longer silently passes (defense in depth: 
write-time validation plus read-time rejection); checkTokenAccess extracted as 
a pure function so the checks are unit-testable without a database; 
authenticateToken returns bool only (removes the dead-code return value 
reserved for 1.4); outdated comment updated.
   - object/channel.go: stale TODO comments cleaned up.
   - object/ormer.go, routers/router.go: token table registration (auto-created 
by Sync2) and five /api routes.
   - run/database_cloud_test.go: added the skipCi build tag, consistent with 
the other nine test files in the repo.
   
   Frontend:
   
   - TokenListPage.js (new): pagination, loading state, status tag, copy 
button, edit/delete actions.
   - TokenEditPage.js (new): create/edit form; the full secret key is shown 
once right after creation; the date picker emits RFC3339.
   - TokenBackend.js (new): API layer; App.js gains the menu entry.
   - Locale files: token strings; properly localized in zh/en, backfilled with 
English in de/es/fr/id/ja/ko/ru (fixes the Chinese values that were mistakenly 
filled in earlier, restoring the English fallback baseline for those languages).
   
   Docs:
   
   - README.md: new LLM API Gateway overview section.
   - docs/llm-api-gateway.md (new): full usage guide (channel configuration, 
token issuance, curl and OpenAI SDK examples, access control semantics, current 
limitations).
   
   Tests:
   
   - object/token_test.go (new): all validateToken branches, secret key 
generation, masking.
   - object/rate_limit_test.go (new): window reset, 51 concurrent callers 
(verifies the mutex fix), stale cleanup, limit<=0.
   - controllers/proxy_test.go: new TestCheckTokenAccess (disabled / expired / 
malformed fail-closed / model allowlist).
   
   # Verification
   
   Automated:
   
   - go build ./... passes.
   - go test -race ./controllers/ passes (including the new 
TestCheckTokenAccess).
   - go test -race on the seven new object tests is all green; the 
51-concurrent rate limit test shows no data race and exact counting.
   
   End-to-end (local port 17000, a DeepSeek channel of type custom with a real 
upstream key):
   
   - Valid token with an allowed model → real upstream reply returned.
   - Model outside the allowlist → 403 model not allowed for this token 
(allowlist enforced).
   - Wrong key → 401 (authentication enforced).
   
   Manual UI checklist (must be done by a human):
   
   - Create a token → the full sk- key is shown once → copy it; the list shows 
only the masked prefix.
   - Call /v1/chat/completions with curl (with a real channel configured).
   - Rate limit: RateLimit=1, two requests back to back → the second gets 429, 
recovered after a minute.
   - Expiration: set to expire in 1 minute → 403 after expiry.
   - Disabled: Status=disabled → 403.
   - Edit/delete: editing without touching the key keeps it working; after 
deletion the old key gets 401.
   - Walk through the whole flow with the Chinese UI.


-- 
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]

Reply via email to