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 %} +