feat(gui): custom login page, session-based auth
Replace nginx auth_basic + HTTP Basic Auth with a styled Flask login form. - Session-based authentication (cookie, session.permanent) - Custom login page with logo, error state, clean form design - CSRF check skipped for /login route - Logout button in sidebar footer - nginx auth_basic removed; ADMIN_PASSWORD restored in .env Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+31
-13
@@ -250,14 +250,6 @@ def to_png_b64(text):
|
||||
return base64.b64encode(buf.getvalue()).decode("ascii")
|
||||
|
||||
|
||||
def _unauthorized():
|
||||
return Response(
|
||||
"Auth required",
|
||||
401,
|
||||
{"WWW-Authenticate": 'Basic realm="WG Admin"'},
|
||||
)
|
||||
|
||||
|
||||
def _get_csrf_token():
|
||||
if "csrf_token" not in session:
|
||||
session["csrf_token"] = secrets.token_hex(32)
|
||||
@@ -266,18 +258,19 @@ def _get_csrf_token():
|
||||
|
||||
app.jinja_env.globals["csrf_token"] = _get_csrf_token
|
||||
|
||||
PUBLIC_PATHS = {"/login", "/static/"}
|
||||
|
||||
|
||||
@app.before_request
|
||||
def _auth():
|
||||
if request.path.startswith("/static/"):
|
||||
return None
|
||||
if request.path == "/login":
|
||||
return None
|
||||
if not ADMIN_PASSWORD:
|
||||
return None
|
||||
auth = request.authorization
|
||||
if not auth:
|
||||
return _unauthorized()
|
||||
if auth.username != ADMIN_USER or auth.password != ADMIN_PASSWORD:
|
||||
return _unauthorized()
|
||||
if not session.get("logged_in"):
|
||||
return redirect(url_for("login", next=request.path))
|
||||
return None
|
||||
|
||||
|
||||
@@ -285,12 +278,37 @@ def _auth():
|
||||
def _csrf_check():
|
||||
if request.method != "POST":
|
||||
return None
|
||||
if request.path == "/login":
|
||||
return None
|
||||
token = request.form.get("csrf_token")
|
||||
if not token or token != session.get("csrf_token"):
|
||||
return Response("CSRF token invalid", 403)
|
||||
return None
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if session.get("logged_in"):
|
||||
return redirect(url_for("index"))
|
||||
error = None
|
||||
if request.method == "POST":
|
||||
user = request.form.get("username", "").strip()
|
||||
pwd = request.form.get("password", "")
|
||||
if user == ADMIN_USER and pwd == ADMIN_PASSWORD:
|
||||
session.clear()
|
||||
session["logged_in"] = True
|
||||
session.permanent = True
|
||||
return redirect(request.args.get("next") or url_for("index"))
|
||||
error = "Неверный логин или пароль"
|
||||
return render_template("login.html", error=error)
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
session.clear()
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
meta = load_meta()
|
||||
|
||||
Reference in New Issue
Block a user