AgentEvalTool/backend/agenteval/web/routers/auth.py
sinohqb 739d586aec feat(backend): v0.4 triggered_by tracking, login gate, compare guard, dashboard stats
- EvalRun.triggered_by 全链路(manual/ai_assistant/cli)+ 迁移 b7d4e6f81c22
- 标准 agenteval-run SKILL.md 纳入版本管理,deploy 脚本同步 + API Key 注入
- 简单登录:AGENTEVAL_ADMIN_PASSWORD + HMAC 会话 token,require_auth 双凭据
- 对比报告限同场景(400)+ 空 results 误判修复
- /api/stats/dashboard 扩展聚合;/api/runs 返回场景/对象名
- 测试 218 → 232
2026-07-28 17:40:54 +08:00

53 lines
1.6 KiB
Python

"""Session login for the web UI.
A single shared password (AGENTEVAL_ADMIN_PASSWORD) gates the SPA. On success
the client receives a stateless HMAC token it sends as X-Auth-Token. Machine
callers (e.g. the OpenClaw skill) keep using X-API-Key and are unaffected.
"""
import hmac
import secrets
from fastapi import APIRouter, Header, HTTPException, status
from pydantic import BaseModel
from agenteval.config import get_settings
router = APIRouter()
_TOKEN_CONTEXT = b"agenteval-web-session"
def session_token() -> str:
"""Derive the stateless session token from configured secrets."""
settings = get_settings()
key = (settings.secret_key or settings.admin_password or "").encode()
return hmac.new(key, _TOKEN_CONTEXT, "sha256").hexdigest()
def verify_session_token(token: str) -> bool:
return bool(token) and hmac.compare_digest(token, session_token())
class LoginRequest(BaseModel):
password: str
@router.post("/login")
def login(request: LoginRequest) -> dict:
configured = get_settings().admin_password
if not configured:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="登录未启用")
if not secrets.compare_digest(request.password, configured):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="密码错误")
return {"token": session_token()}
@router.get("/status")
def auth_status(x_auth_token: str = Header(default="")) -> dict:
auth_required = bool(get_settings().admin_password)
return {
"auth_required": auth_required,
"authenticated": (not auth_required) or verify_session_token(x_auth_token),
}