From a5e1e94fb25d9a67353ad79267d0c724cb52dd49 Mon Sep 17 00:00:00 2001 From: dekun Date: Tue, 12 May 2026 15:53:12 +0800 Subject: [PATCH] fix: show login flashes and CSRF errors; proxy and cookie options for HTTPS deploys Co-authored-by: Cursor --- .env.example | 7 +++++++ app.py | 24 ++++++++++++++++++++++++ templates/base.html | 9 +++++++++ templates/login.html | 5 +++++ 4 files changed, 45 insertions(+) diff --git a/.env.example b/.env.example index 3b78ea1..19ad718 100644 --- a/.env.example +++ b/.env.example @@ -17,3 +17,10 @@ # 调试:1 开启,勿在生产长期开启 # NAV_DEBUG=0 + +# 在 Nginx/Caddy 等反向代理后部署时:信任 X-Forwarded-*,以便 Cookie、CSRF 与 HTTPS 判断正确 +# NAV_TRUST_PROXY=1 +# 站点仅通过 HTTPS 对外时建议开启(浏览器只带 Secure Cookie) +# NAV_SESSION_COOKIE_SECURE=1 +# CSRF 校验仍失败时,可填前端访问的完整 Origin,多个用英文逗号分隔,例如: +# NAV_CSRF_TRUSTED_ORIGINS=https://nav.example.com diff --git a/app.py b/app.py index a859b40..c915bf6 100644 --- a/app.py +++ b/app.py @@ -6,6 +6,7 @@ from typing import Optional from flask import Flask, flash, redirect, render_template, request, url_for from flask_login import LoginManager, current_user, login_required, login_user, logout_user from flask_wtf.csrf import CSRFProtect +from werkzeug.middleware.proxy_fix import ProxyFix from forms import GroupForm, LoginForm, ServiceForm from models import Service, ServiceGroup, User, db @@ -63,6 +64,16 @@ def create_app() -> Flask: app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["WTF_CSRF_TIME_LIMIT"] = None + if os.environ.get("NAV_SESSION_COOKIE_SECURE") == "1": + app.config["SESSION_COOKIE_SECURE"] = True + app.config["REMEMBER_COOKIE_SECURE"] = True + + trusted = os.environ.get("NAV_CSRF_TRUSTED_ORIGINS", "").strip() + if trusted: + app.config["WTF_CSRF_TRUSTED_ORIGINS"] = [ + o.strip() for o in trusted.split(",") if o.strip() + ] + db.init_app(app) login_manager.init_app(app) login_manager.login_view = "login" @@ -271,6 +282,19 @@ def create_app() -> Flask: flash("服务已删除", "success") return redirect(url_for("admin_services")) + if os.environ.get("NAV_TRUST_PROXY") == "1": + app.wsgi_app = ProxyFix( + app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1 + ) + + if not os.environ.get("NAV_SECRET_KEY"): + print( + "[nav] 警告: 未设置 NAV_SECRET_KEY。" + "若使用 gunicorn/uwsgi 等多 worker,或未固定密钥,登录后会话会失效;" + "请在环境变量中配置随机 NAV_SECRET_KEY。", + flush=True, + ) + return app diff --git a/templates/base.html b/templates/base.html index a59a9cf..7634909 100644 --- a/templates/base.html +++ b/templates/base.html @@ -7,6 +7,15 @@ + {% with msgs = get_flashed_messages(with_categories=true) %} + {% if msgs %} +
+ {% for category, message in msgs %} +
{{ message }}
+ {% endfor %} +
+ {% endif %} + {% endwith %} {% block body %}{% endblock %} diff --git a/templates/login.html b/templates/login.html index 040de09..eb9ae00 100644 --- a/templates/login.html +++ b/templates/login.html @@ -6,6 +6,11 @@

本地导航站

{{ form.hidden_tag() }} + {% if request.method == "POST" and form.csrf_token.errors %} + {% for e in form.csrf_token.errors %} + + {% endfor %} + {% endif %}
{{ form.username.label }} {{ form.username(class="") }}