add table prefix
This commit is contained in:
parent
4c70857ff6
commit
f88aca74f2
@ -4,7 +4,9 @@ Bot Manager API 路由
|
||||
"""
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import secrets
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, List
|
||||
from fastapi import APIRouter, HTTPException, Header
|
||||
from pydantic import BaseModel
|
||||
@ -16,9 +18,47 @@ logger = logging.getLogger('app')
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# ============== Admin 配置 ==============
|
||||
ADMIN_USERNAME = "admin"
|
||||
ADMIN_PASSWORD = "Admin123" # 生产环境应使用环境变量
|
||||
TOKEN_EXPIRE_HOURS = 24
|
||||
|
||||
|
||||
# ============== 认证函数 ==============
|
||||
|
||||
async def verify_admin_auth(authorization: Optional[str]) -> tuple[bool, Optional[str]]:
|
||||
"""
|
||||
验证管理员认证
|
||||
|
||||
Args:
|
||||
authorization: Authorization header 值
|
||||
|
||||
Returns:
|
||||
tuple[bool, Optional[str]]: (是否有效, 用户名)
|
||||
"""
|
||||
provided_token = extract_api_key_from_auth(authorization)
|
||||
if not provided_token:
|
||||
return False, None
|
||||
|
||||
pool = get_db_pool_manager().pool
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
# 检查 token 是否有效且未过期
|
||||
await cursor.execute("""
|
||||
SELECT username, expires_at
|
||||
FROM agent_admin_tokens
|
||||
WHERE token = %s
|
||||
AND expires_at > NOW()
|
||||
""", (provided_token,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
return False, None
|
||||
|
||||
return True, row[0]
|
||||
|
||||
|
||||
def verify_auth(authorization: Optional[str]) -> None:
|
||||
"""
|
||||
验证请求认证
|
||||
@ -39,6 +79,26 @@ def verify_auth(authorization: Optional[str]) -> None:
|
||||
|
||||
# ============== Pydantic Models ==============
|
||||
|
||||
# --- Admin 登录相关 ---
|
||||
class AdminLoginRequest(BaseModel):
|
||||
"""管理员登录请求"""
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
class AdminLoginResponse(BaseModel):
|
||||
"""管理员登录响应"""
|
||||
token: str
|
||||
username: str
|
||||
expires_at: str
|
||||
|
||||
|
||||
class AdminVerifyResponse(BaseModel):
|
||||
"""管理员验证响应"""
|
||||
valid: bool
|
||||
username: Optional[str] = None
|
||||
|
||||
|
||||
# --- 模型相关 ---
|
||||
class ModelCreate(BaseModel):
|
||||
"""创建模型请求"""
|
||||
@ -77,7 +137,6 @@ class ModelResponse(BaseModel):
|
||||
class BotCreate(BaseModel):
|
||||
"""创建 Bot 请求"""
|
||||
name: str
|
||||
bot_id: str
|
||||
|
||||
|
||||
class BotUpdate(BaseModel):
|
||||
@ -196,9 +255,23 @@ async def init_bot_manager_tables():
|
||||
|
||||
# SQL 表创建语句
|
||||
tables_sql = [
|
||||
# admin_tokens 表(用于存储登录 token)
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS agent_admin_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(255) NOT NULL,
|
||||
token VARCHAR(255) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
)
|
||||
""",
|
||||
# admin_tokens 索引
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_admin_tokens_token ON agent_admin_tokens(token)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_admin_tokens_expires ON agent_admin_tokens(expires_at)",
|
||||
|
||||
# models 表
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS models (
|
||||
CREATE TABLE IF NOT EXISTS agent_models (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
provider VARCHAR(100) NOT NULL,
|
||||
@ -211,11 +284,11 @@ async def init_bot_manager_tables():
|
||||
)
|
||||
""",
|
||||
# models 索引
|
||||
"CREATE INDEX IF NOT EXISTS idx_models_is_default ON models(is_default)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_models_is_default ON agent_models(is_default)",
|
||||
|
||||
# bots 表
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS bots (
|
||||
CREATE TABLE IF NOT EXISTS agent_bots (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
bot_id VARCHAR(255) NOT NULL UNIQUE,
|
||||
@ -224,13 +297,13 @@ async def init_bot_manager_tables():
|
||||
)
|
||||
""",
|
||||
# bots 索引
|
||||
"CREATE INDEX IF NOT EXISTS idx_bots_bot_id ON bots(bot_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_bots_bot_id ON agent_bots(bot_id)",
|
||||
|
||||
# bot_settings 表
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS bot_settings (
|
||||
bot_id UUID PRIMARY KEY REFERENCES bots(id) ON DELETE CASCADE,
|
||||
model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
CREATE TABLE IF NOT EXISTS agent_bot_settings (
|
||||
bot_id UUID PRIMARY KEY REFERENCES agent_bots(id) ON DELETE CASCADE,
|
||||
model_id UUID REFERENCES agent_models(id) ON DELETE SET NULL,
|
||||
language VARCHAR(10) DEFAULT 'zh',
|
||||
robot_type VARCHAR(50),
|
||||
dataset_ids TEXT,
|
||||
@ -245,9 +318,9 @@ async def init_bot_manager_tables():
|
||||
|
||||
# mcp_servers 表
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS mcp_servers (
|
||||
CREATE TABLE IF NOT EXISTS agent_mcp_servers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
bot_id UUID REFERENCES bots(id) ON DELETE CASCADE,
|
||||
bot_id UUID REFERENCES agent_bots(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
config JSONB NOT NULL,
|
||||
@ -257,22 +330,22 @@ async def init_bot_manager_tables():
|
||||
)
|
||||
""",
|
||||
# mcp_servers 索引
|
||||
"CREATE INDEX IF NOT EXISTS idx_mcp_servers_bot_id ON mcp_servers(bot_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_mcp_servers_enabled ON mcp_servers(enabled)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_mcp_servers_bot_id ON agent_mcp_servers(bot_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_mcp_servers_enabled ON agent_mcp_servers(enabled)",
|
||||
|
||||
# chat_sessions 表
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS chat_sessions (
|
||||
CREATE TABLE IF NOT EXISTS agent_chat_sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
bot_id UUID REFERENCES bots(id) ON DELETE CASCADE,
|
||||
bot_id UUID REFERENCES agent_bots(id) ON DELETE CASCADE,
|
||||
title VARCHAR(500),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
)
|
||||
""",
|
||||
# chat_sessions 索引
|
||||
"CREATE INDEX IF NOT EXISTS idx_chat_sessions_bot_id ON chat_sessions(bot_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_chat_sessions_created ON chat_sessions(created_at DESC)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_chat_sessions_bot_id ON agent_chat_sessions(bot_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_agent_chat_sessions_created ON agent_chat_sessions(created_at DESC)",
|
||||
]
|
||||
|
||||
async with pool.connection() as conn:
|
||||
@ -321,7 +394,7 @@ async def get_models(authorization: Optional[str] = Header(None)):
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
SELECT id, name, provider, model, server, api_key, is_default, created_at, updated_at
|
||||
FROM models
|
||||
FROM agent_models
|
||||
ORDER BY is_default DESC, created_at DESC
|
||||
""")
|
||||
rows = await cursor.fetchall()
|
||||
@ -362,13 +435,13 @@ async def create_model(request: ModelCreate, authorization: Optional[str] = Head
|
||||
if request.is_default:
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("UPDATE models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
await cursor.execute("UPDATE agent_models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
await conn.commit()
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
INSERT INTO models (name, provider, model, server, api_key, is_default)
|
||||
INSERT INTO agent_models (name, provider, model, server, api_key, is_default)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
RETURNING id, created_at, updated_at
|
||||
""", (
|
||||
@ -449,13 +522,13 @@ async def update_model(
|
||||
if request.is_default is True:
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("UPDATE models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
await cursor.execute("UPDATE agent_models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
await conn.commit()
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute(f"""
|
||||
UPDATE models
|
||||
UPDATE agent_models
|
||||
SET {', '.join(update_fields)}
|
||||
WHERE id = %s
|
||||
RETURNING id, name, provider, model, server, api_key, is_default, created_at, updated_at
|
||||
@ -498,7 +571,7 @@ async def delete_model(model_id: str, authorization: Optional[str] = Header(None
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("DELETE FROM models WHERE id = %s RETURNING id", (model_id,))
|
||||
await cursor.execute("DELETE FROM agent_models WHERE id = %s RETURNING id", (model_id,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
@ -528,17 +601,17 @@ async def set_default_model(model_id: str, authorization: Optional[str] = Header
|
||||
# 首先检查模型是否存在
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("SELECT id FROM models WHERE id = %s", (model_id,))
|
||||
await cursor.execute("SELECT id FROM agent_models WHERE id = %s", (model_id,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Model not found")
|
||||
|
||||
# 取消所有默认设置
|
||||
await cursor.execute("UPDATE models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
await cursor.execute("UPDATE agent_models SET is_default = FALSE WHERE is_default = TRUE")
|
||||
|
||||
# 设置新的默认模型
|
||||
await cursor.execute("UPDATE models SET is_default = TRUE WHERE id = %s", (model_id,))
|
||||
await cursor.execute("UPDATE agent_models SET is_default = TRUE WHERE id = %s", (model_id,))
|
||||
|
||||
await conn.commit()
|
||||
|
||||
@ -566,7 +639,7 @@ async def get_bots(authorization: Optional[str] = Header(None)):
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
SELECT id, name, bot_id, created_at, updated_at
|
||||
FROM bots
|
||||
FROM agent_bots
|
||||
ORDER BY created_at DESC
|
||||
""")
|
||||
rows = await cursor.fetchall()
|
||||
@ -599,19 +672,22 @@ async def create_bot(request: BotCreate, authorization: Optional[str] = Header(N
|
||||
|
||||
pool = get_db_pool_manager().pool
|
||||
|
||||
# 自动生成 bot_id
|
||||
bot_id = str(uuid.uuid4())
|
||||
|
||||
try:
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
INSERT INTO bots (name, bot_id)
|
||||
INSERT INTO agent_bots (name, bot_id)
|
||||
VALUES (%s, %s)
|
||||
RETURNING id, created_at, updated_at
|
||||
""", (request.name, request.bot_id))
|
||||
""", (request.name, bot_id))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
# 创建对应的设置记录
|
||||
await cursor.execute("""
|
||||
INSERT INTO bot_settings (bot_id, language)
|
||||
INSERT INTO agent_bot_settings (bot_id, language)
|
||||
VALUES (%s, 'zh')
|
||||
""", (str(row[0]),))
|
||||
|
||||
@ -620,7 +696,7 @@ async def create_bot(request: BotCreate, authorization: Optional[str] = Header(N
|
||||
return BotResponse(
|
||||
id=str(row[0]),
|
||||
name=request.name,
|
||||
bot_id=request.bot_id,
|
||||
bot_id=bot_id,
|
||||
created_at=datetime_to_str(row[1]),
|
||||
updated_at=datetime_to_str(row[2])
|
||||
)
|
||||
@ -671,7 +747,7 @@ async def update_bot(
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute(f"""
|
||||
UPDATE bots
|
||||
UPDATE agent_bots
|
||||
SET {', '.join(update_fields)}
|
||||
WHERE id = %s
|
||||
RETURNING id, name, bot_id, created_at, updated_at
|
||||
@ -710,7 +786,7 @@ async def delete_bot(bot_uuid: str, authorization: Optional[str] = Header(None))
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("DELETE FROM bots WHERE id = %s RETURNING id", (bot_uuid,))
|
||||
await cursor.execute("DELETE FROM agent_bots WHERE id = %s RETURNING id", (bot_uuid,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
@ -745,7 +821,7 @@ async def get_bot_settings(bot_uuid: str, authorization: Optional[str] = Header(
|
||||
SELECT bot_id, model_id,
|
||||
language, robot_type, dataset_ids, system_prompt, user_identifier,
|
||||
enable_memori, tool_response, skills, updated_at
|
||||
FROM bot_settings
|
||||
FROM agent_bot_settings
|
||||
WHERE bot_id = %s
|
||||
""", (bot_uuid,))
|
||||
row = await cursor.fetchone()
|
||||
@ -759,7 +835,7 @@ async def get_bot_settings(bot_uuid: str, authorization: Optional[str] = Header(
|
||||
if model_id:
|
||||
await cursor.execute("""
|
||||
SELECT id, name, provider, model, server, api_key
|
||||
FROM models WHERE id = %s
|
||||
FROM agent_models WHERE id = %s
|
||||
""", (model_id,))
|
||||
model_row = await cursor.fetchone()
|
||||
if model_row:
|
||||
@ -821,7 +897,7 @@ async def update_bot_settings(
|
||||
if model_id_value:
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("SELECT id FROM models WHERE id = %s", (model_id_value,))
|
||||
await cursor.execute("SELECT id FROM agent_models WHERE id = %s", (model_id_value,))
|
||||
if not await cursor.fetchone():
|
||||
raise HTTPException(status_code=400, detail=f"Model with id '{request.model_id}' not found")
|
||||
# 使用 NULL 或占位符
|
||||
@ -864,7 +940,7 @@ async def update_bot_settings(
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
# 检查设置是否存在
|
||||
await cursor.execute("SELECT bot_id FROM bot_settings WHERE bot_id = %s", (bot_uuid,))
|
||||
await cursor.execute("SELECT bot_id FROM agent_bot_settings WHERE bot_id = %s", (bot_uuid,))
|
||||
if not await cursor.fetchone():
|
||||
# 不存在则创建
|
||||
# 需要分别处理带占位符和不带占位符的字段
|
||||
@ -935,13 +1011,13 @@ async def update_bot_settings(
|
||||
|
||||
# 构建 SQL:混合使用占位符和 NULL
|
||||
values_clause = ", ".join(insert_placeholders)
|
||||
sql = f"INSERT INTO bot_settings ({', '.join(insert_fields)}) VALUES ({values_clause})"
|
||||
sql = f"INSERT INTO agent_bot_settings ({', '.join(insert_fields)}) VALUES ({values_clause})"
|
||||
|
||||
await cursor.execute(sql, insert_values)
|
||||
else:
|
||||
# 存在则更新
|
||||
await cursor.execute(f"""
|
||||
UPDATE bot_settings
|
||||
UPDATE agent_bot_settings
|
||||
SET {', '.join(update_fields)}
|
||||
WHERE bot_id = %s
|
||||
""", values)
|
||||
@ -973,7 +1049,7 @@ async def get_bot_sessions(bot_uuid: str, authorization: Optional[str] = Header(
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
SELECT id, bot_id, title, created_at, updated_at
|
||||
FROM chat_sessions
|
||||
FROM agent_chat_sessions
|
||||
WHERE bot_id = %s
|
||||
ORDER BY updated_at DESC
|
||||
""", (bot_uuid,))
|
||||
@ -1015,13 +1091,13 @@ async def create_session(
|
||||
# 验证 Bot 是否存在
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("SELECT id FROM bots WHERE id = %s", (bot_uuid,))
|
||||
await cursor.execute("SELECT id FROM agent_bots WHERE id = %s", (bot_uuid,))
|
||||
if not await cursor.fetchone():
|
||||
raise HTTPException(status_code=404, detail="Bot not found")
|
||||
|
||||
# 创建会话
|
||||
await cursor.execute("""
|
||||
INSERT INTO chat_sessions (bot_id, title)
|
||||
INSERT INTO agent_chat_sessions (bot_id, title)
|
||||
VALUES (%s, %s)
|
||||
RETURNING id, created_at, updated_at
|
||||
""", (bot_uuid, request.title))
|
||||
@ -1056,7 +1132,7 @@ async def delete_session(session_id: str, authorization: Optional[str] = Header(
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("DELETE FROM chat_sessions WHERE id = %s RETURNING id", (session_id,))
|
||||
await cursor.execute("DELETE FROM agent_chat_sessions WHERE id = %s RETURNING id", (session_id,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
@ -1089,7 +1165,7 @@ async def get_mcp_servers(bot_uuid: str, authorization: Optional[str] = Header(N
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("""
|
||||
SELECT id, bot_id, name, type, config, enabled, created_at, updated_at
|
||||
FROM mcp_servers
|
||||
FROM agent_mcp_servers
|
||||
WHERE bot_id = %s
|
||||
ORDER BY created_at DESC
|
||||
""", (bot_uuid,))
|
||||
@ -1134,12 +1210,12 @@ async def update_mcp_servers(
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
# 删除旧的 MCP 配置
|
||||
await cursor.execute("DELETE FROM mcp_servers WHERE bot_id = %s", (bot_uuid,))
|
||||
await cursor.execute("DELETE FROM agent_mcp_servers WHERE bot_id = %s", (bot_uuid,))
|
||||
|
||||
# 插入新的 MCP 配置
|
||||
for server in servers:
|
||||
await cursor.execute("""
|
||||
INSERT INTO mcp_servers (bot_id, name, type, config, enabled)
|
||||
INSERT INTO agent_mcp_servers (bot_id, name, type, config, enabled)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
""", (
|
||||
bot_uuid,
|
||||
@ -1181,13 +1257,13 @@ async def add_mcp_server(
|
||||
# 验证 Bot 是否存在
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("SELECT id FROM bots WHERE id = %s", (bot_uuid,))
|
||||
await cursor.execute("SELECT id FROM agent_bots WHERE id = %s", (bot_uuid,))
|
||||
if not await cursor.fetchone():
|
||||
raise HTTPException(status_code=404, detail="Bot not found")
|
||||
|
||||
# 创建 MCP 服务器
|
||||
await cursor.execute("""
|
||||
INSERT INTO mcp_servers (bot_id, name, type, config, enabled)
|
||||
INSERT INTO agent_mcp_servers (bot_id, name, type, config, enabled)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
RETURNING id, created_at, updated_at
|
||||
""", (
|
||||
@ -1237,7 +1313,7 @@ async def delete_mcp_server(
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"DELETE FROM mcp_servers WHERE id = %s AND bot_id = %s RETURNING id",
|
||||
"DELETE FROM agent_mcp_servers WHERE id = %s AND bot_id = %s RETURNING id",
|
||||
(mcp_id, bot_uuid)
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
@ -1248,3 +1324,96 @@ async def delete_mcp_server(
|
||||
await conn.commit()
|
||||
|
||||
return SuccessResponse(success=True, message="MCP server deleted successfully")
|
||||
|
||||
|
||||
# ============== Admin 登录 API ==============
|
||||
|
||||
@router.post("/api/v1/admin/login", response_model=AdminLoginResponse)
|
||||
async def admin_login(request: AdminLoginRequest):
|
||||
"""
|
||||
管理员登录
|
||||
|
||||
Args:
|
||||
request: 登录请求(用户名和密码)
|
||||
|
||||
Returns:
|
||||
AdminLoginResponse: 登录成功返回 token
|
||||
"""
|
||||
# 硬编码验证账号密码
|
||||
if request.username != ADMIN_USERNAME or request.password != ADMIN_PASSWORD:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="用户名或密码错误"
|
||||
)
|
||||
|
||||
pool = get_db_pool_manager().pool
|
||||
|
||||
# 生成 token
|
||||
token = secrets.token_urlsafe(32)
|
||||
expires_at = datetime.now() + timedelta(hours=TOKEN_EXPIRE_HOURS)
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
# 清理该用户的旧 token
|
||||
await cursor.execute("DELETE FROM agent_admin_tokens WHERE username = %s", (request.username,))
|
||||
|
||||
# 保存新 token
|
||||
await cursor.execute("""
|
||||
INSERT INTO agent_admin_tokens (username, token, expires_at)
|
||||
VALUES (%s, %s, %s)
|
||||
""", (request.username, token, expires_at))
|
||||
|
||||
await conn.commit()
|
||||
|
||||
return AdminLoginResponse(
|
||||
token=token,
|
||||
username=request.username,
|
||||
expires_at=expires_at.isoformat()
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/v1/admin/verify", response_model=AdminVerifyResponse)
|
||||
async def admin_verify(authorization: Optional[str] = Header(None)):
|
||||
"""
|
||||
验证管理员 token 是否有效
|
||||
|
||||
Args:
|
||||
authorization: Bearer token
|
||||
|
||||
Returns:
|
||||
AdminVerifyResponse: 验证结果
|
||||
"""
|
||||
valid, username = await verify_admin_auth(authorization)
|
||||
|
||||
return AdminVerifyResponse(
|
||||
valid=valid,
|
||||
username=username
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/v1/admin/logout", response_model=SuccessResponse)
|
||||
async def admin_logout(authorization: Optional[str] = Header(None)):
|
||||
"""
|
||||
管理员登出(删除 token)
|
||||
|
||||
Args:
|
||||
authorization: Bearer token
|
||||
|
||||
Returns:
|
||||
SuccessResponse: 登出结果
|
||||
"""
|
||||
provided_token = extract_api_key_from_auth(authorization)
|
||||
if not provided_token:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Authorization header is required"
|
||||
)
|
||||
|
||||
pool = get_db_pool_manager().pool
|
||||
|
||||
async with pool.connection() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("DELETE FROM agent_admin_tokens WHERE token = %s", (provided_token,))
|
||||
await conn.commit()
|
||||
|
||||
return SuccessResponse(success=True, message="Logged out successfully")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user