fix: WebSocket 403 — require_active_plugin skips WebSocket requests
Simpler approach: require_active_plugin._check() now accepts Request parameter and returns early for WebSocket upgrade requests. No route splitting needed — all routes stay in their original router.
This commit is contained in:
+5
-1
@@ -237,7 +237,11 @@ def require_active_plugin(plugin_name: str):
|
|||||||
already have their own auth dependencies (require_permission, etc.).
|
already have their own auth dependencies (require_permission, etc.).
|
||||||
This check only verifies plugin activation status.
|
This check only verifies plugin activation status.
|
||||||
"""
|
"""
|
||||||
async def _check() -> None:
|
async def _check(request: Request) -> None:
|
||||||
|
# Skip plugin check for WebSocket connections — WS auth is handled
|
||||||
|
# inside the endpoint itself via session cookie verification.
|
||||||
|
if request.headers.get("upgrade", "").lower() == "websocket":
|
||||||
|
return
|
||||||
from app.core.permission_registry import get_permission_registry
|
from app.core.permission_registry import get_permission_registry
|
||||||
try:
|
try:
|
||||||
registry = get_permission_registry()
|
registry = get_permission_registry()
|
||||||
|
|||||||
+3
-13
@@ -439,27 +439,17 @@ def create_app() -> FastAPI:
|
|||||||
# Skip WebSocket routes — the wrapper breaks WS parameter
|
# Skip WebSocket routes — the wrapper breaks WS parameter
|
||||||
# resolution and returns JSONResponse instead of WS close.
|
# resolution and returns JSONResponse instead of WS close.
|
||||||
from starlette.routing import WebSocketRoute
|
from starlette.routing import WebSocketRoute
|
||||||
http_routes = []
|
|
||||||
ws_routes = []
|
|
||||||
for route in router.routes:
|
for route in router.routes:
|
||||||
if isinstance(route, WebSocketRoute):
|
if isinstance(route, WebSocketRoute):
|
||||||
ws_routes.append(route)
|
continue
|
||||||
else:
|
|
||||||
if hasattr(route, 'endpoint'):
|
if hasattr(route, 'endpoint'):
|
||||||
route.endpoint = wrap_plugin_route(route.endpoint)
|
route.endpoint = wrap_plugin_route(route.endpoint)
|
||||||
http_routes.append(route)
|
# Add active-plugin check as a router-level dependency
|
||||||
# Register HTTP routes with active-plugin check
|
# (require_active_plugin skips WebSocket requests internally)
|
||||||
router.routes = http_routes
|
|
||||||
app.include_router(
|
app.include_router(
|
||||||
router,
|
router,
|
||||||
dependencies=[Depends(require_active_plugin(plugin_name))],
|
dependencies=[Depends(require_active_plugin(plugin_name))],
|
||||||
)
|
)
|
||||||
# Register WebSocket routes WITHOUT active-plugin check
|
|
||||||
# (WebSocket auth is handled inside the endpoint itself)
|
|
||||||
if ws_routes:
|
|
||||||
ws_router = APIRouter()
|
|
||||||
ws_router.routes = ws_routes
|
|
||||||
app.include_router(ws_router)
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.error(f"Failed to register route {route_def.module}.{route_def.router_attr}: {exc}")
|
logger.error(f"Failed to register route {route_def.module}.{route_def.router_attr}: {exc}")
|
||||||
break
|
break
|
||||||
|
|||||||
Reference in New Issue
Block a user