This commit is contained in:
Raykov-MS 2026-09-02 13:21:27 +03:00
parent 0d9d7af779
commit faaf50694f
3 changed files with 82 additions and 49 deletions

View File

@ -0,0 +1,58 @@
"""Публичные пути для AuthorizationMiddleware: SPA и infra, без /api."""
ABSOLUTE_PUBLIC_PATHS = (
"",
"/",
"/healthcheck",
"/healthcheck2",
"/healthz",
"/readyz",
)
START_PUBLIC_PREFIXES = (
"/static",
"/back-static",
"/openapi.json",
"/docs",
"/docs-local",
"/login",
"/task",
"/project",
"/forms",
"/table",
"/admin_panel",
"/dicts",
"/svod",
"/index",
"/favicon",
"/assets",
"/images",
)
def with_root(path: str, root_path: str) -> tuple[str, ...]:
if not root_path:
return (path,)
root = root_path.rstrip("/")
if path == "":
return (path, root)
return (path, f"{root}{path}")
def public_endpoint_specs(root_path: str = "") -> list[tuple[str, str]]:
"""Пары (mode, path): mode is 'absolute' or 'start'."""
specs: list[tuple[str, str]] = []
seen: set[tuple[str, str]] = set()
for path in ABSOLUTE_PUBLIC_PATHS:
for full in with_root(path, root_path):
item = ("absolute", full)
if item not in seen:
seen.add(item)
specs.append(item)
for path in START_PUBLIC_PREFIXES:
for full in with_root(path, root_path):
item = ("start", full)
if item not in seen:
seen.add(item)
specs.append(item)
return specs

View File

@ -18,6 +18,7 @@ from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from src.api.v1.router import api_router
from src.core.config import settings
from src.core.exception_handlers import register_exception_handlers
from src.core.public_paths import public_endpoint_specs
from src.db.base import engine
from src.db.session import create_tables
@ -186,58 +187,12 @@ async def readyz(response: Response):
if not settings.DEBUG:
_search = {"absolute": SearchType.ABSOLUTE, "start": SearchType.START}
app.add_middleware(
AuthorizationMiddleware,
open_endpoints=[
OpenEndpoint(path="", type_search=SearchType.ABSOLUTE),
OpenEndpoint(path=settings.ROOT_PATH + "", type_search=SearchType.ABSOLUTE),
OpenEndpoint(path="/", type_search=SearchType.ABSOLUTE),
OpenEndpoint(path=settings.ROOT_PATH + "/", type_search=SearchType.ABSOLUTE),
OpenEndpoint(path="/healthcheck", type_search=SearchType.ABSOLUTE),
OpenEndpoint(
path=settings.ROOT_PATH + "/healthcheck",
type_search=SearchType.ABSOLUTE,
),
OpenEndpoint(path="/healthcheck2", type_search=SearchType.ABSOLUTE),
OpenEndpoint(
path=settings.ROOT_PATH + "/healthcheck2",
type_search=SearchType.ABSOLUTE,
),
OpenEndpoint(path="/healthz", type_search=SearchType.ABSOLUTE),
OpenEndpoint(
path=settings.ROOT_PATH + "/healthz",
type_search=SearchType.ABSOLUTE,
),
OpenEndpoint(path="/readyz", type_search=SearchType.ABSOLUTE),
OpenEndpoint(
path=settings.ROOT_PATH + "/readyz",
type_search=SearchType.ABSOLUTE,
),
OpenEndpoint(path="/static", type_search=SearchType.START),
OpenEndpoint(
path=settings.ROOT_PATH + "/static",
type_search=SearchType.START,
),
OpenEndpoint(path="/back-static", type_search=SearchType.START),
OpenEndpoint(
path=settings.ROOT_PATH + "/back-static",
type_search=SearchType.START,
),
OpenEndpoint(path="/openapi.json", type_search=SearchType.START),
OpenEndpoint(
path=settings.ROOT_PATH + "/openapi.json",
type_search=SearchType.START,
),
OpenEndpoint(path="/docs", type_search=SearchType.START),
OpenEndpoint(
path=settings.ROOT_PATH + "/docs",
type_search=SearchType.START,
),
OpenEndpoint(path="/docs-local", type_search=SearchType.START),
OpenEndpoint(
path=settings.ROOT_PATH + "/docs-local",
type_search=SearchType.START,
),
OpenEndpoint(path=path, type_search=_search[mode])
for mode, path in public_endpoint_specs(settings.ROOT_PATH)
],
)

View File

@ -0,0 +1,20 @@
from src.core.public_paths import public_endpoint_specs
def test_login_page_is_public_without_root():
specs = public_endpoint_specs("")
assert ("start", "/login") in specs
assert ("absolute", "/") in specs
def test_login_page_is_public_with_root_path():
specs = public_endpoint_specs("/aurora/apps/fastapi-tsygankov-test")
assert ("start", "/login") in specs
assert ("start", "/aurora/apps/fastapi-tsygankov-test/login") in specs
def test_api_routes_are_not_public():
specs = public_endpoint_specs("/aurora/apps/fastapi-tsygankov-test")
paths = [path for _, path in specs]
assert not any(path == "/api" or path.startswith("/api/") for path in paths)
assert not any("/api/v1" in path for path in paths)