fix(auth): role-aware post-login landing to avoid 403 for non-MeasurementTec

Login always redirected to measure.select_recipe, which is gated by
@role_required("MeasurementTec"). A Maker-only (or Metrologist-only) user
was therefore bounced straight to a 403 right after a successful login.

Add _post_login_landing() which selects the landing endpoint from the user's
roles (MeasurementTec -> measure, Maker -> maker recipes, Metrologist ->
statistics, admin -> users, else profile). Used for both fresh login and the
already-authenticated short-circuit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-05 08:24:20 +00:00
parent b325eb3512
commit 2eb5c51353
+24 -10
View File
@@ -39,15 +39,32 @@ def role_required(*roles):
return decorator
def _post_login_landing():
"""Pick the landing endpoint based on the logged-in user's roles.
A Maker-only user must not be bounced to /measure (MeasurementTec-only),
which would raise a 403 right after login. Order of preference follows the
primary operator flow first, then editing, analysis, admin.
"""
user = session.get("user", {})
roles = user.get("roles", [])
if "MeasurementTec" in roles:
return url_for("measure.select_recipe")
if "Maker" in roles:
return url_for("maker.recipe_list")
if "Metrologist" in roles:
return url_for("statistics.dashboard")
if user.get("is_admin"):
return url_for("admin.user_list")
return url_for("auth.profile")
@auth_bp.route("/login", methods=["GET", "POST"])
def login():
"""Login page and form handler."""
# Se già loggato, redirect a home
# Se già loggato, redirect alla home in base al ruolo
if session.get("api_key"):
try:
return redirect(url_for("measure.select_recipe"))
except Exception:
return redirect(url_for("auth.profile"))
return redirect(_post_login_landing())
if request.method == "POST":
username = request.form.get("username", "").strip()
@@ -91,11 +108,8 @@ def login():
flash(_("Benvenuto, %(name)s!", name=user.get("display_name", username)), "success")
# Redirect dopo login
try:
return redirect(url_for("measure.select_recipe"))
except Exception:
return redirect(url_for("auth.profile"))
# Redirect dopo login (in base al ruolo)
return redirect(_post_login_landing())
except Exception as e:
flash(_("Errore di connessione al server: %(error)s", error=str(e)), "error")