refactor(plugin_system): 移除路由级认证,引入端点级安全依赖
之前的插件路由认证机制通过在 `RouterInfo` 中设置 `auth_required` 标志,对整个路由组件统一应用API密钥验证。这种方式缺乏灵活性,无法对单个端点进行细粒度的安全控制。 本次重构移除了 `auth_required` 机制,转而引入一个可重用的 FastAPI 依赖项 `VerifiedDep`。插件开发者现在可以按需将其应用到需要保护的特定端点上,从而实现更灵活、更精确的访问控制。 `hello_world_plugin` 已更新,以演示新的认证方式。 BREAKING CHANGE: 移除了 `RouterInfo` 中的 `auth_required` 属性。所有依赖此属性进行认证的插件路由都需要更新,改为在需要保护的端点上使用 `VerifiedDep` 依赖项。
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import random
|
import random
|
||||||
from typing import Any, ClassVar
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
from mmc.src.plugin_system.base.base_http_component import BaseRouterComponent
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
from src.common.security import VerifiedDep
|
||||||
|
|
||||||
# 修正导入路径,让Pylance不再抱怨
|
# 修正导入路径,让Pylance不再抱怨
|
||||||
from src.plugin_system import (
|
from src.plugin_system import (
|
||||||
@@ -21,6 +21,7 @@ from src.plugin_system import (
|
|||||||
register_plugin,
|
register_plugin,
|
||||||
)
|
)
|
||||||
from src.plugin_system.base.base_event import HandlerResult
|
from src.plugin_system.base.base_event import HandlerResult
|
||||||
|
from src.plugin_system.base.base_http_component import BaseRouterComponent
|
||||||
from src.plugin_system.base.component_types import InjectionRule, InjectionType
|
from src.plugin_system.base.component_types import InjectionRule, InjectionType
|
||||||
|
|
||||||
logger = get_logger("hello_world_plugin")
|
logger = get_logger("hello_world_plugin")
|
||||||
@@ -208,7 +209,7 @@ class HelloWorldRouter(BaseRouterComponent):
|
|||||||
|
|
||||||
def register_endpoints(self) -> None:
|
def register_endpoints(self) -> None:
|
||||||
@self.router.get("/greet", summary="返回一个问候消息")
|
@self.router.get("/greet", summary="返回一个问候消息")
|
||||||
def greet():
|
def greet(_=VerifiedDep):
|
||||||
"""这个端点返回一个固定的问候语。"""
|
"""这个端点返回一个固定的问候语。"""
|
||||||
return {"message": "Hello from your new API endpoint!"}
|
return {"message": "Hello from your new API endpoint!"}
|
||||||
|
|
||||||
@@ -218,7 +219,7 @@ class HelloWorldPlugin(BasePlugin):
|
|||||||
"""一个包含四大核心组件和高级配置功能的入门示例插件。"""
|
"""一个包含四大核心组件和高级配置功能的入门示例插件。"""
|
||||||
|
|
||||||
plugin_name = "hello_world_plugin"
|
plugin_name = "hello_world_plugin"
|
||||||
enable_plugin = True
|
enable_plugin: bool = True
|
||||||
dependencies: ClassVar = []
|
dependencies: ClassVar = []
|
||||||
python_dependencies: ClassVar = []
|
python_dependencies: ClassVar = []
|
||||||
config_file_name = "config.toml"
|
config_file_name = "config.toml"
|
||||||
|
|||||||
@@ -30,3 +30,8 @@ async def get_api_key(api_key: str = Security(api_key_header_auth)) -> str:
|
|||||||
detail="无效的API密钥",
|
detail="无效的API密钥",
|
||||||
)
|
)
|
||||||
return api_key
|
return api_key
|
||||||
|
|
||||||
|
# 创建一个可重用的依赖项,供插件开发者在其需要验证的端点上使用
|
||||||
|
# 用法: @router.get("/protected_route", dependencies=[VerifiedDep])
|
||||||
|
# 或者: async def my_endpoint(_=VerifiedDep): ...
|
||||||
|
VerifiedDep = Depends(get_api_key)
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from .component_types import ComponentType, RouterInfo
|
from .component_types import ComponentType, RouterInfo
|
||||||
|
|
||||||
|
|
||||||
class BaseRouterComponent(ABC):
|
class BaseRouterComponent(ABC):
|
||||||
"""
|
"""
|
||||||
用于暴露HTTP端点的组件基类。
|
用于暴露HTTP端点的组件基类。
|
||||||
|
|||||||
@@ -449,8 +449,6 @@ class MaiMessages:
|
|||||||
class RouterInfo(ComponentInfo):
|
class RouterInfo(ComponentInfo):
|
||||||
"""路由组件信息"""
|
"""路由组件信息"""
|
||||||
|
|
||||||
auth_required: bool = False
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__post_init__()
|
super().__post_init__()
|
||||||
self.component_type = ComponentType.ROUTER
|
self.component_type = ComponentType.ROUTER
|
||||||
|
|||||||
@@ -390,7 +390,6 @@ class ComponentRegistry:
|
|||||||
logger.info("插件HTTP端点功能已禁用,跳过路由注册")
|
logger.info("插件HTTP端点功能已禁用,跳过路由注册")
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
from src.common.security import get_api_key
|
|
||||||
from src.common.server import get_global_server
|
from src.common.server import get_global_server
|
||||||
|
|
||||||
router_name = router_info.name
|
router_name = router_info.name
|
||||||
@@ -408,14 +407,10 @@ class ComponentRegistry:
|
|||||||
# 5. 生成唯一的URL前缀
|
# 5. 生成唯一的URL前缀
|
||||||
prefix = f"/plugins/{plugin_name}"
|
prefix = f"/plugins/{plugin_name}"
|
||||||
|
|
||||||
# 6. 根据需要应用安全依赖项
|
# 6. 注册路由,并使用插件名作为API文档的分组标签
|
||||||
dependencies = []
|
# 移除了dependencies参数,因为现在由每个端点自行决定是否需要验证
|
||||||
if router_info.auth_required:
|
|
||||||
dependencies.append(Depends(get_api_key))
|
|
||||||
|
|
||||||
# 7. 注册路由,并使用插件名作为API文档的分组标签
|
|
||||||
server.app.include_router(
|
server.app.include_router(
|
||||||
plugin_router, prefix=prefix, tags=[plugin_name], dependencies=dependencies
|
plugin_router, prefix=prefix, tags=[plugin_name]
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(f"成功将插件 '{plugin_name}' 的路由组件 '{router_name}' 挂载到: {prefix}")
|
logger.debug(f"成功将插件 '{plugin_name}' 的路由组件 '{router_name}' 挂载到: {prefix}")
|
||||||
@@ -880,6 +875,7 @@ class ComponentRegistry:
|
|||||||
def get_plugin_components(self, plugin_name: str) -> list["ComponentInfo"]:
|
def get_plugin_components(self, plugin_name: str) -> list["ComponentInfo"]:
|
||||||
"""获取插件的所有组件"""
|
"""获取插件的所有组件"""
|
||||||
plugin_info = self.get_plugin_info(plugin_name)
|
plugin_info = self.get_plugin_info(plugin_name)
|
||||||
|
logger.info(plugin_info.components)
|
||||||
return plugin_info.components if plugin_info else []
|
return plugin_info.components if plugin_info else []
|
||||||
|
|
||||||
def get_plugin_config(self, plugin_name: str) -> dict:
|
def get_plugin_config(self, plugin_name: str) -> dict:
|
||||||
|
|||||||
Reference in New Issue
Block a user