修复
This commit is contained in:
@@ -190,6 +190,85 @@ def _resolve_hub_embed_service(body: dict) -> tuple[str | None, str | None, str
|
||||
return base, next_path, None
|
||||
|
||||
|
||||
def _resolve_gate_scout_embed_service(
|
||||
body: dict,
|
||||
) -> tuple[str | None, str | None, str | None, str | None]:
|
||||
"""返回 (base_origin, default_next_path, embed_kind, error_detail)。"""
|
||||
sid = body.get("service_id")
|
||||
base = (body.get("base_url") or "").strip().rstrip("/")
|
||||
next_path = (body.get("next") or "/dashboard").strip() or "/dashboard"
|
||||
embed_kind = (body.get("embed_kind") or "").strip().lower()
|
||||
if not next_path.startswith("/"):
|
||||
next_path = "/" + next_path
|
||||
|
||||
if sid:
|
||||
svc = db.session.get(Service, int(sid))
|
||||
if not svc or not svc.is_gate_scout_embed():
|
||||
return None, None, None, "服务不存在或未标记为 Gate 扫单嵌入"
|
||||
base = svc.build_origin()
|
||||
embed_kind = (svc.embed_kind or "").strip().lower()
|
||||
if not body.get("next") or next_path == "/dashboard":
|
||||
p = (svc.path or "/dashboard").strip() or "/dashboard"
|
||||
next_path = p if p.startswith("/") else "/" + p
|
||||
|
||||
if not base:
|
||||
return None, None, None, "缺少 base_url"
|
||||
if embed_kind in ("gate_exec", "exec"):
|
||||
login_path = "/login"
|
||||
else:
|
||||
login_path = "/api/auth/login"
|
||||
return base, next_path, login_path, None
|
||||
|
||||
|
||||
def _gate_scout_api_login(
|
||||
base: str, username: str, password: str, *, login_path: str, next_path: str
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""服务端登录 Gate 扫单/执行器,返回 (完整 embed_auth_url, error_detail)。"""
|
||||
payload = json.dumps(
|
||||
{"username": username, "password": password, "embed": "1", "next": next_path}
|
||||
).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
f"{base.rstrip('/')}{login_path}",
|
||||
data=payload,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"X-Nav-Embed": "1",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
raw = resp.read().decode("utf-8", errors="replace")
|
||||
except urllib.error.HTTPError as e:
|
||||
try:
|
||||
err_body = e.read().decode("utf-8", errors="replace")
|
||||
detail = json.loads(err_body).get("detail", err_body)
|
||||
except Exception:
|
||||
detail = str(e)
|
||||
return None, detail or "Gate 扫单登录失败"
|
||||
except Exception as e:
|
||||
return None, f"无法连接 Gate 服务: {e}"
|
||||
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return None, "Gate 服务返回非 JSON"
|
||||
if not data.get("ok"):
|
||||
return None, data.get("detail") or "登录失败"
|
||||
embed_url = (data.get("embed_auth_url") or "").strip()
|
||||
if embed_url.startswith("/"):
|
||||
embed_url = base.rstrip("/") + embed_url
|
||||
if not embed_url:
|
||||
token = (data.get("session_token") or "").strip()
|
||||
if token:
|
||||
q = urlencode({"token": token, "next": next_path, "embed": "1"})
|
||||
embed_url = f"{base.rstrip('/')}/embed-auth?{q}"
|
||||
if not embed_url:
|
||||
return None, "未返回 embed_auth_url,请确认云端已设置 NAV_EMBED_SESSION=1 并重启 PM2"
|
||||
return embed_url, None
|
||||
|
||||
|
||||
def create_app() -> Flask:
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = os.environ.get("NAV_SECRET_KEY") or secrets.token_hex(32)
|
||||
@@ -265,6 +344,8 @@ def create_app() -> Flask:
|
||||
"index.html",
|
||||
grouped=grouped,
|
||||
hub_auto_login=os.environ.get("NAV_HUB_AUTO_LOGIN", "").strip() == "1",
|
||||
gate_scout_auto_login=os.environ.get("NAV_GATE_SCOUT_AUTO_LOGIN", "").strip()
|
||||
== "1",
|
||||
)
|
||||
|
||||
@app.route("/api/embed/hub-login", methods=["POST"])
|
||||
@@ -297,6 +378,47 @@ def create_app() -> Flask:
|
||||
embed_url = f"{base}/embed-auth?{q}"
|
||||
return jsonify({"ok": True, "embed_auth_url": embed_url, "next": next_path})
|
||||
|
||||
@app.route("/api/embed/gate-scout-login", methods=["POST"])
|
||||
@csrf.exempt
|
||||
@login_required
|
||||
def api_embed_gate_scout_login():
|
||||
"""
|
||||
本地导航代登录 Gate 扫描端/执行器:服务端请求 /api/auth/login 或 /login,
|
||||
再让 iframe 打开 /embed-auth 写入 SameSite=None Cookie。
|
||||
"""
|
||||
body = request.get_json(silent=True) or {}
|
||||
username = (
|
||||
body.get("username") or os.environ.get("NAV_GATE_SCOUT_USERNAME") or ""
|
||||
).strip()
|
||||
password = body.get("password")
|
||||
if password is None:
|
||||
password = os.environ.get("NAV_GATE_SCOUT_PASSWORD") or ""
|
||||
password = str(password)
|
||||
|
||||
base, next_path, login_path, err = _resolve_gate_scout_embed_service(body)
|
||||
if err:
|
||||
return jsonify({"ok": False, "detail": err}), 400
|
||||
if not username or not password:
|
||||
return jsonify(
|
||||
{
|
||||
"ok": False,
|
||||
"detail": "缺少 Gate 扫单用户名或密码(可配置 NAV_GATE_SCOUT_USERNAME / NAV_GATE_SCOUT_PASSWORD)",
|
||||
}
|
||||
), 400
|
||||
|
||||
embed_url, err = _gate_scout_api_login(
|
||||
base,
|
||||
username,
|
||||
password,
|
||||
login_path=login_path,
|
||||
next_path=next_path,
|
||||
)
|
||||
if err:
|
||||
status = 401 if "登录" in err or "401" in err or "密码" in err else 502
|
||||
return jsonify({"ok": False, "detail": err}), status
|
||||
|
||||
return jsonify({"ok": True, "embed_auth_url": embed_url, "next": next_path})
|
||||
|
||||
@app.route("/api/embed/hub-instance-url", methods=["POST"])
|
||||
@csrf.exempt
|
||||
@login_required
|
||||
@@ -620,12 +742,12 @@ def _ensure_gate_scout_services() -> None:
|
||||
db.session.flush()
|
||||
|
||||
defs = (
|
||||
("Gate 扫描端", scout_host, scout_port, scout_path, 0),
|
||||
("Gate 下单执行器", exec_host, exec_port, exec_path, 10),
|
||||
("Gate 扫描端", scout_host, scout_port, scout_path, 0, "gate_scout"),
|
||||
("Gate 下单执行器", exec_host, exec_port, exec_path, 10, "gate_exec"),
|
||||
)
|
||||
added = 0
|
||||
updated = 0
|
||||
for name, h, port, path, order in defs:
|
||||
for name, h, port, path, order, embed_k in defs:
|
||||
existing = Service.query.filter_by(group_id=g.id, name=name).first()
|
||||
if existing:
|
||||
if update_existing and (
|
||||
@@ -633,11 +755,16 @@ def _ensure_gate_scout_services() -> None:
|
||||
or existing.host != h
|
||||
or existing.port != port
|
||||
or existing.path != path
|
||||
or (existing.embed_kind or "") != embed_k
|
||||
):
|
||||
existing.scheme = scheme
|
||||
existing.host = h
|
||||
existing.port = port
|
||||
existing.path = path
|
||||
existing.embed_kind = embed_k
|
||||
updated += 1
|
||||
elif not (existing.embed_kind or "").strip():
|
||||
existing.embed_kind = embed_k
|
||||
updated += 1
|
||||
continue
|
||||
db.session.add(
|
||||
@@ -649,7 +776,7 @@ def _ensure_gate_scout_services() -> None:
|
||||
path=path,
|
||||
sort_order=order,
|
||||
group_id=g.id,
|
||||
embed_kind="",
|
||||
embed_kind=embed_k,
|
||||
)
|
||||
)
|
||||
added += 1
|
||||
|
||||
Reference in New Issue
Block a user