修复
This commit is contained in:
+55
-13
@@ -3,6 +3,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from nav_session_auth import nav_embed_session_active, request_is_https
|
||||
|
||||
|
||||
def nav_embed_allowed() -> bool:
|
||||
@@ -19,26 +22,33 @@ def nav_embed_origins() -> str:
|
||||
|
||||
|
||||
def nav_session_middleware_kwargs() -> dict:
|
||||
"""
|
||||
LocalNav 等跨站 iframe 内登录须 SameSite=None + Secure(仅 HTTPS 站点有效)。
|
||||
NAV_EMBED_SESSION=1 强制开启;auto 时在配置了 NAV_EMBED_ORIGINS 时开启。
|
||||
"""
|
||||
raw = (os.getenv("NAV_EMBED_SESSION") or "auto").strip().lower()
|
||||
if raw in ("0", "false", "no", "off"):
|
||||
"""跨站 iframe:SameSite=None;https_only 保持 False,由响应 patch 补 Secure。"""
|
||||
if not nav_embed_session_active():
|
||||
return {"same_site": "lax", "https_only": False}
|
||||
if raw in ("1", "true", "yes", "on"):
|
||||
return {"same_site": "none", "https_only": True}
|
||||
if raw == "auto":
|
||||
origins = nav_embed_origins()
|
||||
if origins and origins != "*":
|
||||
return {"same_site": "none", "https_only": True}
|
||||
return {"same_site": "lax", "https_only": False}
|
||||
return {"same_site": "none", "https_only": False}
|
||||
|
||||
|
||||
def install_proxy_headers(app) -> None:
|
||||
if (os.getenv("NAV_TRUST_PROXY") or "").strip().lower() not in (
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
"on",
|
||||
):
|
||||
return
|
||||
try:
|
||||
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
||||
|
||||
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def install_nav_embed(app) -> None:
|
||||
if not nav_embed_allowed():
|
||||
return
|
||||
origins = nav_embed_origins()
|
||||
install_proxy_headers(app)
|
||||
|
||||
@app.middleware("http")
|
||||
async def _nav_embed_frame_headers(request, call_next):
|
||||
@@ -48,4 +58,36 @@ def install_nav_embed(app) -> None:
|
||||
else:
|
||||
parts = " ".join(o.strip() for o in origins.split(",") if o.strip())
|
||||
response.headers["Content-Security-Policy"] = f"frame-ancestors 'self' {parts}"
|
||||
if nav_embed_session_active():
|
||||
_patch_set_cookie_for_embed(response, request)
|
||||
return response
|
||||
|
||||
|
||||
def _patch_set_cookie_for_embed(response, request) -> None:
|
||||
"""HTTPS 访问时强制 session Cookie 为 SameSite=None; Secure。"""
|
||||
force = (os.getenv("NAV_EMBED_FORCE_SECURE") or "1").strip().lower() in (
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
"on",
|
||||
)
|
||||
if not request_is_https(request) and not force:
|
||||
return
|
||||
raw = response.headers.get("set-cookie")
|
||||
if not raw:
|
||||
return
|
||||
|
||||
def _fix_one(part: str) -> str:
|
||||
p = part.strip()
|
||||
if not p or "session=" not in p.lower():
|
||||
return p
|
||||
p = re.sub(r";\s*SameSite=[^;]*", "", p, flags=re.I)
|
||||
p = re.sub(r";\s*Secure(?=;|$)", "", p, flags=re.I)
|
||||
p += "; Secure; SameSite=none"
|
||||
return p
|
||||
|
||||
if "," in raw and "session=" in raw.lower():
|
||||
parts = re.split(r",(?=\s*[^;,]+=)", raw)
|
||||
response.headers["set-cookie"] = ", ".join(_fix_one(x) for x in parts)
|
||||
else:
|
||||
response.headers["set-cookie"] = _fix_one(raw)
|
||||
|
||||
Reference in New Issue
Block a user