修复
This commit is contained in:
@@ -156,17 +156,18 @@ try:
|
|||||||
_root = _Path(__file__).resolve().parent.parent.parent
|
_root = _Path(__file__).resolve().parent.parent.parent
|
||||||
if str(_root) not in sys.path:
|
if str(_root) not in sys.path:
|
||||||
sys.path.insert(0, str(_root))
|
sys.path.insert(0, str(_root))
|
||||||
from nav_embed import install_nav_embed
|
from nav_embed import install_nav_embed, nav_session_middleware_kwargs
|
||||||
|
|
||||||
install_nav_embed(app)
|
install_nav_embed(app)
|
||||||
|
_sess_kw = nav_session_middleware_kwargs()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
_sess_kw = {"same_site": "lax", "https_only": False}
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
SessionMiddleware,
|
SessionMiddleware,
|
||||||
secret_key=settings.app.session_secret,
|
secret_key=settings.app.session_secret,
|
||||||
max_age=60 * 60 * 24 * 7,
|
max_age=60 * 60 * 24 * 7,
|
||||||
same_site="lax",
|
same_site=_sess_kw.get("same_site", "lax"),
|
||||||
https_only=False,
|
https_only=bool(_sess_kw.get("https_only", False)),
|
||||||
)
|
)
|
||||||
app.mount("/static", StaticFiles(directory=str(root_dir / "static")), name="static")
|
app.mount("/static", StaticFiles(directory=str(root_dir / "static")), name="static")
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ module.exports = {
|
|||||||
// 本地导航 iframe 嵌入(勿写进 config.yaml,须在此或 pm2 ecosystem)
|
// 本地导航 iframe 嵌入(勿写进 config.yaml,须在此或 pm2 ecosystem)
|
||||||
// NAV_ALLOW_EMBED: "true",
|
// NAV_ALLOW_EMBED: "true",
|
||||||
// NAV_EMBED_ORIGINS: "http://192.168.8.6:5070",
|
// NAV_EMBED_ORIGINS: "http://192.168.8.6:5070",
|
||||||
|
// NAV_EMBED_SESSION: "1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -18,6 +18,23 @@ def nav_embed_origins() -> str:
|
|||||||
return (os.getenv("NAV_EMBED_ORIGINS") or "*").strip() or "*"
|
return (os.getenv("NAV_EMBED_ORIGINS") or "*").strip() or "*"
|
||||||
|
|
||||||
|
|
||||||
|
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"):
|
||||||
|
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}
|
||||||
|
|
||||||
|
|
||||||
def install_nav_embed(app) -> None:
|
def install_nav_embed(app) -> None:
|
||||||
if not nav_embed_allowed():
|
if not nav_embed_allowed():
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -186,18 +186,19 @@ def create_app(settings: Settings) -> FastAPI:
|
|||||||
_root = _Path(__file__).resolve().parent.parent.parent
|
_root = _Path(__file__).resolve().parent.parent.parent
|
||||||
if str(_root) not in sys.path:
|
if str(_root) not in sys.path:
|
||||||
sys.path.insert(0, str(_root))
|
sys.path.insert(0, str(_root))
|
||||||
from nav_embed import install_nav_embed
|
from nav_embed import install_nav_embed, nav_session_middleware_kwargs
|
||||||
|
|
||||||
install_nav_embed(app)
|
install_nav_embed(app)
|
||||||
|
_sess_kw = nav_session_middleware_kwargs()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
_sess_kw = {"same_site": "lax", "https_only": False}
|
||||||
app.add_middleware(GZipMiddleware, minimum_size=800)
|
app.add_middleware(GZipMiddleware, minimum_size=800)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
SessionMiddleware,
|
SessionMiddleware,
|
||||||
secret_key=settings.app.session_secret,
|
secret_key=settings.app.session_secret,
|
||||||
max_age=60 * 60 * 24 * 7,
|
max_age=60 * 60 * 24 * 7,
|
||||||
same_site="lax",
|
same_site=_sess_kw.get("same_site", "lax"),
|
||||||
https_only=False,
|
https_only=bool(_sess_kw.get("https_only", False)),
|
||||||
)
|
)
|
||||||
root_dir = Path(__file__).resolve().parent.parent
|
root_dir = Path(__file__).resolve().parent.parent
|
||||||
templates = Jinja2Templates(directory=str(root_dir / "templates"))
|
templates = Jinja2Templates(directory=str(root_dir / "templates"))
|
||||||
@@ -318,6 +319,24 @@ def create_app(settings: Settings) -> FastAPI:
|
|||||||
return RedirectResponse("/dashboard", status_code=302)
|
return RedirectResponse("/dashboard", status_code=302)
|
||||||
return templates.TemplateResponse("login.html", {"request": request, "error": "用户名或密码错误"})
|
return templates.TemplateResponse("login.html", {"request": request, "error": "用户名或密码错误"})
|
||||||
|
|
||||||
|
@app.post("/api/auth/login")
|
||||||
|
async def api_auth_login(request: Request) -> JSONResponse:
|
||||||
|
if not settings.auth.enabled:
|
||||||
|
return JSONResponse({"ok": True, "redirect": "/dashboard"})
|
||||||
|
try:
|
||||||
|
body = await request.json()
|
||||||
|
except Exception:
|
||||||
|
return JSONResponse({"ok": False, "detail": "请求格式错误"}, status_code=400)
|
||||||
|
username = str(body.get("username") or "").strip()
|
||||||
|
password = str(body.get("password") or "")
|
||||||
|
ok_user = username == app.state.auth_user
|
||||||
|
ok_pass = _hash_password(password) == app.state.auth_password_hash
|
||||||
|
if ok_user and ok_pass:
|
||||||
|
request.session["logged_in"] = True
|
||||||
|
request.session["username"] = username
|
||||||
|
return JSONResponse({"ok": True, "redirect": "/dashboard"})
|
||||||
|
return JSONResponse({"ok": False, "detail": "用户名或密码错误"}, status_code=401)
|
||||||
|
|
||||||
@app.get("/logout")
|
@app.get("/logout")
|
||||||
async def logout(request: Request) -> RedirectResponse:
|
async def logout(request: Request) -> RedirectResponse:
|
||||||
request.session.clear()
|
request.session.clear()
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ module.exports = {
|
|||||||
// 本地导航 iframe 嵌入(勿写进 config.yaml,须在此或 pm2 ecosystem)
|
// 本地导航 iframe 嵌入(勿写进 config.yaml,须在此或 pm2 ecosystem)
|
||||||
// NAV_ALLOW_EMBED: "true",
|
// NAV_ALLOW_EMBED: "true",
|
||||||
// NAV_EMBED_ORIGINS: "http://192.168.8.6:5070",
|
// NAV_EMBED_ORIGINS: "http://192.168.8.6:5070",
|
||||||
|
// NAV_EMBED_SESSION: "1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -24,14 +24,57 @@
|
|||||||
<div class="matrix-login-badge">SECURE CHANNEL</div>
|
<div class="matrix-login-badge">SECURE CHANNEL</div>
|
||||||
<div class="matrix-login-glitch" data-text="> AUTHENTICATE">> AUTHENTICATE</div>
|
<div class="matrix-login-glitch" data-text="> AUTHENTICATE">> AUTHENTICATE</div>
|
||||||
<p class="matrix-login-sub">MATRIX // GATE USDT PERP FUNNEL · 未授权区域禁止访问</p>
|
<p class="matrix-login-sub">MATRIX // GATE USDT PERP FUNNEL · 未授权区域禁止访问</p>
|
||||||
<form method="post" action="/login" class="matrix-login-form">
|
<form id="matrixLoginForm" method="post" action="/login" class="matrix-login-form">
|
||||||
<label class="matrix-label">操作员 ID</label>
|
<label class="matrix-label">操作员 ID</label>
|
||||||
<input class="matrix-input" type="text" name="username" required autocomplete="username" />
|
<input class="matrix-input" type="text" name="username" required autocomplete="username" />
|
||||||
<label class="matrix-label">密钥</label>
|
<label class="matrix-label">密钥</label>
|
||||||
<input class="matrix-input" type="password" name="password" required autocomplete="current-password" />
|
<input class="matrix-input" type="password" name="password" required autocomplete="current-password" />
|
||||||
<button type="submit" class="matrix-btn matrix-btn-full matrix-btn-pulse">建立会话</button>
|
<button type="submit" class="matrix-btn matrix-btn-full matrix-btn-pulse">建立会话</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="matrix-error">{{ error }}</div>
|
<div class="matrix-error" id="matrixLoginError">{{ error }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById("matrixLoginForm");
|
||||||
|
var errEl = document.getElementById("matrixLoginError");
|
||||||
|
if (!form) return;
|
||||||
|
form.addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (errEl) errEl.textContent = "";
|
||||||
|
var fd = new FormData(form);
|
||||||
|
var btn = form.querySelector('button[type="submit"]');
|
||||||
|
if (btn) btn.disabled = true;
|
||||||
|
fetch("/api/auth/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
||||||
|
credentials: "same-origin",
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: fd.get("username"),
|
||||||
|
password: fd.get("password"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(function (r) {
|
||||||
|
return r.json().then(function (j) {
|
||||||
|
return { ok: r.ok, body: j };
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function (x) {
|
||||||
|
if (x.ok && x.body && x.body.redirect) {
|
||||||
|
window.location.href = x.body.redirect;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (errEl) {
|
||||||
|
errEl.textContent = (x.body && x.body.detail) || "登录失败";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
if (errEl) errEl.textContent = "网络错误或会话 Cookie 被拦截(iframe 嵌入须 HTTPS + NAV_EMBED_ORIGINS)";
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
if (btn) btn.disabled = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user