#!/usr/bin/env python3 """API Key 管理路由 — 创建/列表/删除长期有效的 API 密钥""" import secrets import time import logging from aiohttp import web from ..utils.auth import panel_auth logger = logging.getLogger(__name__) # 持久化 key: 内存 + DB 双写 # 格式: {key_string: {name, created_at, last_used}} API_KEYS: dict[str, dict] = {} def _load_keys_from_db(app): """从数据库恢复 API keys""" try: db = app.get("sensu_db") if not db: sm = app.get("service_manager") if sm: try: db = sm.get_service("sensu_db") except Exception: pass if db: import json raw = db.get_config("api_keys", "{}") stored = json.loads(raw) if raw else {} for k, v in stored.items(): API_KEYS[k] = v if stored: logger.info(f"🔑 从数据库恢复了 {len(stored)} 个 API Key") except Exception as e: logger.warning(f"API Key 恢复失败: {e}") def _save_keys_to_db(app): """持久化 API keys 到数据库""" try: db = app.get("sensu_db") if not db: sm = app.get("service_manager") if sm: try: db = sm.get_service("sensu_db") except Exception: pass if db: import json db.set_config("api_keys", json.dumps(API_KEYS)) except Exception as e: logger.debug(f"API Key 持久化失败: {e}") def validate_api_key(token: str) -> dict | None: """验证 API Key,返回 key_info 或 None""" if token in API_KEYS: API_KEYS[token]["last_used"] = time.time() return API_KEYS[token] return None def setup_routes(app, prefix=""): """注册 API Key 管理路由""" _load_keys_from_db(app) app["api_keys"] = API_KEYS # ── 列表 ── async def list_keys(req): keys = [] for k, v in API_KEYS.items(): keys.append({ "key": k[:8] + "..." + k[-4:], # 脱敏显示 "full_key": k, # 仅创建时返回完整 key "name": v.get("name", ""), "created_at": v.get("created_at", 0), "last_used": v.get("last_used", 0), }) return web.json_response({"keys": keys}) # ── 创建 ── async def create_key(req): try: data = await req.json() name = data.get("name", "").strip() if not name: return web.json_response({"error": "名称不能为空"}, status=400) key = "sk-" + secrets.token_hex(24) # sk- + 48 hex = 51 chars API_KEYS[key] = { "name": name, "created_at": time.time(), "last_used": 0, } _save_keys_to_db(req.app) logger.info(f"🔑 API Key 已创建: {name} ({key[:12]}...)") return web.json_response({ "ok": True, "key": key, "name": name, "created_at": API_KEYS[key]["created_at"], }) except Exception as e: return web.json_response({"error": str(e)}, status=500) # ── 删除 ── async def delete_key(req): try: data = await req.json() full_key = data.get("key", "") if full_key in API_KEYS: name = API_KEYS[full_key]["name"] del API_KEYS[full_key] _save_keys_to_db(req.app) logger.info(f"🔑 API Key 已删除: {name}") return web.json_response({"ok": True}) return web.json_response({"error": "Key 不存在"}, status=404) except Exception as e: return web.json_response({"error": str(e)}, status=500) app.router.add_get(f"{prefix}/api/apikeys", panel_auth(list_keys)) app.router.add_post(f"{prefix}/api/apikeys", panel_auth(create_key)) app.router.add_delete(f"{prefix}/api/apikeys", panel_auth(delete_key)) logger.info(f"🔑 API Key 管理路由已注册 ({prefix}/api/apikeys)")