feat(core): 初始化 Key-IP Sentinel 服务与部署骨架
- 搭建 FastAPI、Redis、PostgreSQL、Nginx 与 Docker Compose 基础结构 - 实现反向代理、首用绑定、拦截告警、归档任务和管理接口 - 提供 Vue3 管理后台初版,以及 uv/requirements 双依赖配置
This commit is contained in:
49
app/api/auth.py
Normal file
49
app/api/auth.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from redis.asyncio import Redis
|
||||
|
||||
from app.config import Settings
|
||||
from app.core.ip_utils import extract_client_ip
|
||||
from app.core.security import (
|
||||
clear_login_failures,
|
||||
create_admin_jwt,
|
||||
ensure_login_allowed,
|
||||
register_login_failure,
|
||||
verify_admin_password,
|
||||
)
|
||||
from app.dependencies import get_redis, get_settings
|
||||
from app.schemas.auth import LoginRequest, TokenResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/admin/api", tags=["auth"])
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
async def login(
|
||||
payload: LoginRequest,
|
||||
request: Request,
|
||||
settings: Settings = Depends(get_settings),
|
||||
redis: Redis | None = Depends(get_redis),
|
||||
) -> TokenResponse:
|
||||
if redis is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Login service is unavailable because Redis is offline.",
|
||||
)
|
||||
|
||||
client_ip = extract_client_ip(request, settings)
|
||||
await ensure_login_allowed(redis, client_ip, settings)
|
||||
|
||||
if not verify_admin_password(payload.password, settings):
|
||||
await register_login_failure(redis, client_ip, settings)
|
||||
logger.warning("Admin login failed.", extra={"client_ip": client_ip})
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid admin password.")
|
||||
|
||||
await clear_login_failures(redis, client_ip)
|
||||
token, expires_in = create_admin_jwt(settings)
|
||||
logger.info("Admin login succeeded.", extra={"client_ip": client_ip})
|
||||
return TokenResponse(access_token=token, expires_in=expires_in)
|
||||
Reference in New Issue
Block a user