- S1/S2: 会话锁改 RLock(持锁可重入调 _save_sessions);cookie 时间戳改整数+解析兼容(会话创建/验证往返已实测) - M1: api_login 接入 verify_user(账号锁定/失败计数生效),DB 无用户时才回退 config 凭据 - M3+L5: handler _do_auth 统一入口加 IP 白名单检查;未知 auth_type 返回 401 - M4+L10: metrics 与无版本 /api/admin/ 加入受保护端点 - M6: debug 日志敏感头脱敏;main.py 不再打印 token 前缀 - M7: auth_token.txt / auth_sessions.json chmod 600 - M9: verify_user 统一错误消息防用户枚举 - M10: AdminAPI 复用共享 APIAuthManager(修复会话状态分裂) - L7: check_auth 大小写不敏感匹配(防 /API/.. 大写绕过) - L8: token_expires_at 显式 is not None 判断 - L11: verify_password 对非 bcrypt 哈希回退 PBKDF2(重写,修复 ValueError 分支不落回退的问题)
123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
管理员API处理器
|
|
提供认证相关API(无 keys 管理)
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
from core.api_auth import APIAuthManager, require_auth
|
|
|
|
|
|
class AdminAPI:
|
|
"""管理员API处理器"""
|
|
|
|
def __init__(self, config: dict):
|
|
self.config = config
|
|
# 复用共享认证管理器(router 注入的 config['_auth_manager']),
|
|
# 避免多实例各自持有会话表导致状态分裂
|
|
self.auth_manager = config.get('_auth_manager') or APIAuthManager(config)
|
|
if config.get('_auth_manager') is None:
|
|
config['_auth_manager'] = self.auth_manager
|
|
|
|
def handle_request(self, handler, method, path, query_params):
|
|
"""处理管理员API请求"""
|
|
|
|
# 解析路径
|
|
parts = path.strip('/').split('/')
|
|
|
|
# 根路径 - 列出API
|
|
if len(parts) == 0 or parts[0] == '':
|
|
self._api_overview(handler)
|
|
return
|
|
|
|
action = parts[0]
|
|
|
|
if action == 'auth':
|
|
self._handle_auth(handler, method, query_params)
|
|
elif action == 'sessions':
|
|
self._handle_sessions(handler, method, parts[1:] if len(parts) > 1 else [])
|
|
elif action == 'stats':
|
|
self._handle_stats(handler)
|
|
else:
|
|
handler.send_json_response({
|
|
"error": f"Unknown admin action: {action}",
|
|
"available_actions": ["auth", "sessions", "stats"]
|
|
}, 404)
|
|
|
|
def _api_overview(self, handler):
|
|
"""API概览"""
|
|
handler.send_json_response({
|
|
"name": "HYC Admin API",
|
|
"version": "1.0",
|
|
"description": "管理员认证API",
|
|
"endpoints": {
|
|
"GET /api/v2/admin/sessions": "列出活跃会话",
|
|
"DELETE /api/v2/admin/sessions/{session_id}": "销毁会话",
|
|
"POST /api/v2/admin/auth/verify": "验证认证状态",
|
|
"GET /api/v2/admin/stats": "获取认证统计"
|
|
},
|
|
"authentication": {
|
|
"methods": [
|
|
"Authorization: Bearer <token>",
|
|
"X-API-Key: <token>",
|
|
"Cookie: hyc_auth=<session>",
|
|
"?key=<token>"
|
|
]
|
|
}
|
|
})
|
|
|
|
def _handle_auth(self, handler, method, query_params):
|
|
"""处理认证相关"""
|
|
# POST /api/v2/admin/auth/verify - 验证当前认证状态
|
|
if method == 'POST':
|
|
auth_result = handler.auth_result if hasattr(handler, 'auth_result') else {}
|
|
|
|
if auth_result.get('authenticated'):
|
|
handler.send_json_response({
|
|
"authenticated": True,
|
|
"level": auth_result.get('level'),
|
|
"key_id": auth_result.get('key_id'),
|
|
"name": auth_result.get('name'),
|
|
"permissions": auth_result.get('permissions', [])
|
|
})
|
|
else:
|
|
handler.send_json_response({
|
|
"authenticated": False
|
|
}, 401)
|
|
|
|
else:
|
|
handler.send_json_response({"error": "Invalid method"}, 405)
|
|
|
|
def _handle_sessions(self, handler, method, parts):
|
|
"""处理会话管理"""
|
|
if method == 'GET':
|
|
# 列出活跃会话(auth_manager 内部加锁遍历)
|
|
sessions = self.auth_manager.list_sessions()
|
|
|
|
handler.send_json_response({
|
|
"sessions": sessions,
|
|
"count": len(sessions)
|
|
})
|
|
|
|
elif method == 'DELETE' and len(parts) >= 1 and parts[0]:
|
|
session_id = parts[0]
|
|
success = self.auth_manager.destroy_session(session_id)
|
|
if success:
|
|
handler.send_json_response({
|
|
"success": True,
|
|
"message": f"Session {session_id} destroyed"
|
|
})
|
|
else:
|
|
handler.send_json_response({"error": "Session not found"}, 404)
|
|
|
|
else:
|
|
handler.send_json_response({"error": "Invalid request"}, 400)
|
|
|
|
def _handle_stats(self, handler):
|
|
"""获取认证统计"""
|
|
stats = self.auth_manager.get_stats()
|
|
handler.send_json_response(stats)
|