chy88 0a1eeb9ddf refactor(admin): 收敛后台接口封装与页面状态逻辑
- 简化绑定和日志接口的查询、序列化与前端数据请求路径
- 统一登录流程与前端 API 调用层,补充后台图标依赖
- 抽取通用异步状态处理,减少多个管理页面的重复逻辑
2026-03-04 00:18:47 +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%