chy88 380a78283e feat(frontend): 打磨管理台交互体验与可访问性
- 优化 Dashboard、Bindings、Logs、Settings 的布局、筛选区与信息层级
- 增加筛选状态同步、未保存提醒、运行时反馈和趋势表视图
- 补充跳转主内容、aria live、键盘导航与移动端触控细节
2026-03-04 00:18:59 +08:00

Key-IP Sentinel

Key-IP Sentinel is a FastAPI-based reverse proxy that enforces first-use IP binding for model API keys before traffic reaches a downstream New API service.

Features

  • First-use bind with HMAC-SHA256 token hashing, Redis cache-aside, and PostgreSQL CIDR matching.
  • Streaming reverse proxy built on httpx.AsyncClient and FastAPI StreamingResponse.
  • Trusted proxy IP extraction that only accepts X-Real-IP from configured upstream networks.
  • Redis-backed intercept alert counters with webhook delivery and PostgreSQL audit logs.
  • Admin API protected by JWT and Redis-backed login lockout.
  • Vue 3 + Element Plus admin console for dashboarding, binding operations, audit logs, and live runtime settings.
  • Docker Compose deployment with Nginx, app, Redis, and PostgreSQL.

Repository Layout

sentinel/
├── app/
├── db/
├── nginx/
├── frontend/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── README.md

Runtime Notes

  • Redis stores binding cache, alert counters, daily dashboard metrics, and mutable runtime settings.
  • PostgreSQL stores authoritative token bindings and intercept logs.
  • Archive retention removes inactive bindings from the active table after ARCHIVE_DAYS. A later request from the same token will bind again on first use.
  • SENTINEL_FAILSAFE_MODE=closed rejects requests when both Redis and PostgreSQL are unavailable. open allows traffic through.

Local Development

Backend

  1. Install uv and ensure Python 3.13 is available.
  2. Create the environment and sync dependencies:
uv sync
  1. Copy .env.example to .env and update secrets plus addresses.
  2. Start PostgreSQL and Redis.
  3. Run the API:
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 7000

Frontend

  1. Install dependencies:
cd frontend
npm install
  1. Start Vite dev server:
npm run dev

The Vite config proxies /admin/api/* to http://127.0.0.1:7000.

Dependency Management

  • Local Python development uses uv via pyproject.toml.
  • Container builds still use requirements.txt because the Dockerfile is intentionally minimal and matches the delivery requirements.

Production Deployment

1. Prepare environment

  1. Copy .env.example to .env.
  2. Replace SENTINEL_HMAC_SECRET, ADMIN_PASSWORD, and ADMIN_JWT_SECRET.
  3. Verify DOWNSTREAM_URL points to the internal New API service.
  4. Keep PG_DSN aligned with the fixed PostgreSQL container password in docker-compose.yml, or update both together.

2. Build the frontend bundle

cd frontend
npm install
npm run build
cd ..

This produces frontend/dist, which Nginx serves at /admin/ui/.

3. Provide TLS assets

Place certificate files at:

  • nginx/ssl/server.crt
  • nginx/ssl/server.key

4. Start the stack

docker compose up --build -d

Services:

  • https://<host>/ forwards model API traffic through Sentinel.
  • https://<host>/admin/ui/ serves the admin console.
  • https://<host>/admin/api/* serves the admin API.
  • https://<host>/health exposes the app health check.

Admin API Summary

  • POST /admin/api/login
  • GET /admin/api/dashboard
  • GET /admin/api/bindings
  • POST /admin/api/bindings/unbind
  • PUT /admin/api/bindings/ip
  • POST /admin/api/bindings/ban
  • POST /admin/api/bindings/unban
  • GET /admin/api/logs
  • GET /admin/api/logs/export
  • GET /admin/api/settings
  • PUT /admin/api/settings

All admin endpoints except /admin/api/login require Authorization: Bearer <jwt>.

Key Implementation Details

  • app/proxy/handler.py keeps the downstream response fully streamed, including SSE responses.
  • app/core/ip_utils.py never trusts client-supplied X-Forwarded-For.
  • app/services/binding_service.py batches last_used_at updates every 5 seconds through an asyncio.Queue.
  • app/services/alert_service.py pushes webhooks once the Redis counter reaches the configured threshold.
  • app/services/archive_service.py prunes stale bindings on a scheduler interval.

Suggested Smoke Checks

  1. GET /health returns {"status":"ok"}.
  2. A first request with a new bearer token creates a binding in PostgreSQL and Redis.
  3. A second request from the same IP is allowed and refreshes last_used_at.
  4. A request from a different IP is rejected with 403 and creates an intercept_logs record.
  5. /admin/api/login returns a JWT and the frontend can load /admin/api/dashboard.
Description
No description provided
Readme 255 KiB
Languages
Python 48.3%
Vue 35.7%
CSS 10.4%
JavaScript 5.2%
HTML 0.2%
Other 0.2%