优化whitelist白名单函数机制,api路径更简短

This commit is contained in:
jingrow 2025-10-29 20:05:44 +08:00
parent dab5fa4cda
commit 6895bf380b

View File

@ -19,11 +19,11 @@ from jingrow.utils.jingrow_api import get_logged_user
logger = logging.getLogger(__name__)
router = APIRouter()
# 确保 apps 目录在 sys.path 中(仅初始化一次)
# 确保 app 目录在 sys.path 中(仅初始化一次)
_apps_path_initialized = False
def _ensure_apps_on_sys_path():
"""确保 apps 目录在 sys.path 中,支持跨 app 导入"""
"""确保 app 目录在 sys.path 中,支持跨 app 导入"""
global _apps_path_initialized
if _apps_path_initialized:
return
@ -31,8 +31,16 @@ def _ensure_apps_on_sys_path():
try:
project_root = Path(__file__).resolve().parents[4]
apps_dir = project_root / "apps"
if apps_dir.exists() and str(apps_dir) not in sys.path:
sys.path.insert(0, str(apps_dir))
# 读取 apps.txt添加各 app 的根目录apps/<app>
apps_txt = apps_dir / "apps.txt"
if apps_txt.exists():
for app_name in apps_txt.read_text().splitlines():
app_name = app_name.strip()
if app_name:
app_root_dir = apps_dir / app_name
if app_root_dir.exists() and str(app_root_dir) not in sys.path:
sys.path.insert(0, str(app_root_dir))
except Exception:
pass
finally:
@ -92,24 +100,17 @@ async def _process_whitelist_call(request: Request, full_module_path: str):
# 确保 apps 目录在 sys.path 中(支持跨 app 导入)
_ensure_apps_on_sys_path()
# 先导入模块,确保装饰器执行
module_info = parse_module_path(full_module_path)
module = import_module(module_info['module_path'])
# 解析路径并导入
modulename = ".".join(full_module_path.split('.')[:-1])
methodname = full_module_path.split('.')[-1]
module = import_module(modulename)
func = getattr(module, methodname)
# 使用实际模块路径匹配白名单(装饰器注册时使用 func.__module__
actual_module_name = module.__name__
actual_whitelist_path = f"{actual_module_name}.{module_info['function_name']}"
# 检查白名单:优先使用实际模块路径,也支持原始路径
whitelist_info = None
for check_path in [actual_whitelist_path, full_module_path]:
if is_whitelisted(check_path):
whitelist_info = get_whitelisted_function(check_path)
break
# 检查白名单(装饰器注册时使用 func.__module__
actual_whitelist_path = f"{module.__name__}.{methodname}"
whitelist_info = get_whitelisted_function(actual_whitelist_path)
if whitelist_info:
func = whitelist_info['function']
# 检查 HTTP 方法
if request.method not in whitelist_info['methods']:
raise HTTPException(status_code=405, detail=f"Method {request.method} not allowed")
@ -118,19 +119,8 @@ async def _process_whitelist_call(request: Request, full_module_path: str):
if not whitelist_info['allow_guest']:
if not await authenticate_request(request, whitelist_info['allow_guest']):
raise HTTPException(status_code=401, detail="Authentication required")
# 获取请求数据并调用函数
request_data = await _get_request_data(request)
result = func(**request_data)
return JSONResponse(content={"success": True, "data": result})
# 非白名单:按原逻辑调用模块函数
function_name = module_info['function_name']
if not hasattr(module, function_name):
raise HTTPException(status_code=404, detail=f"Function {function_name} not found")
func = getattr(module, function_name)
# 调用函数
request_data = await _get_request_data(request)
result = func(**request_data)
@ -146,7 +136,7 @@ async def _process_whitelist_call(request: Request, full_module_path: str):
@router.api_route("/{module_path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def handle_request(request: Request, module_path: str):
"""
动态路由支持完整点分路径例如 demo.demo.pagetype.hello_world.hello_world.test_whitelist
兼容旧路径直接传入完整点分路径 '<package.module.function>'
"""
return await _process_whitelist_call(request, module_path)
@ -154,7 +144,7 @@ async def handle_request(request: Request, module_path: str):
@router.api_route("/{app}/{module_path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def handle_request_with_app_prefix(request: Request, app: str, module_path: str):
"""
动态路由支持 app 前缀格式例如 /demo/demo.pagetype.hello_world.hello_world.test_whitelist
新路径支持以 app 作为前缀例如 app.module.function
"""
full_module_path = f"{app}.{module_path}"
return await _process_whitelist_call(request, full_module_path)