fix 401
This commit is contained in:
parent
0d9d7af779
commit
faaf50694f
58
api/src/core/public_paths.py
Normal file
58
api/src/core/public_paths.py
Normal 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
|
||||||
@ -18,6 +18,7 @@ from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
|||||||
from src.api.v1.router import api_router
|
from src.api.v1.router import api_router
|
||||||
from src.core.config import settings
|
from src.core.config import settings
|
||||||
from src.core.exception_handlers import register_exception_handlers
|
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.base import engine
|
||||||
from src.db.session import create_tables
|
from src.db.session import create_tables
|
||||||
|
|
||||||
@ -186,58 +187,12 @@ async def readyz(response: Response):
|
|||||||
|
|
||||||
|
|
||||||
if not settings.DEBUG:
|
if not settings.DEBUG:
|
||||||
|
_search = {"absolute": SearchType.ABSOLUTE, "start": SearchType.START}
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
AuthorizationMiddleware,
|
AuthorizationMiddleware,
|
||||||
open_endpoints=[
|
open_endpoints=[
|
||||||
OpenEndpoint(path="", type_search=SearchType.ABSOLUTE),
|
OpenEndpoint(path=path, type_search=_search[mode])
|
||||||
OpenEndpoint(path=settings.ROOT_PATH + "", type_search=SearchType.ABSOLUTE),
|
for mode, path in public_endpoint_specs(settings.ROOT_PATH)
|
||||||
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,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
20
api/tests/unit/test_public_paths.py
Normal file
20
api/tests/unit/test_public_paths.py
Normal 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)
|
||||||
Loading…
x
Reference in New Issue
Block a user