fix(csrf): centraliser l'injection des tokens CSRF via un dcc.Store et un callback pattern-matching

Remplace les 7 callbacks CSRF individuels (un par formulaire, avec IDs string
page-spécifiques) par un seul dcc.Store(id="csrf-token") dans le layout principal
et un callback pattern-matching Output({"type": "csrf-input", "index": ALL}).
Évite les erreurs Dash "id non trouvé dans le layout" sans recourir à
suppress_callback_exceptions=True.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-06-24 05:26:07 +02:00
parent c228f7be55
commit c99f4d970e
7 changed files with 100 additions and 50 deletions
+11 -14
View File
@@ -1,7 +1,6 @@
import dash_bootstrap_components as dbc
from dash import Input, Output, callback, dcc, html, register_page
from dash import dcc, html, register_page
from flask_login import current_user
from flask_wtf.csrf import generate_csrf
NAME = "Mon compte"
@@ -42,7 +41,11 @@ def layout(error: str | None = None, password_changed: str | None = None, **_):
method="POST",
action="/auth/change-password",
children=[
dcc.Input(type="hidden", id="csrf-change", name="csrf_token"),
dcc.Input(
type="hidden",
id={"type": "csrf-input", "index": "change"},
name="csrf_token",
),
dbc.Label("Mot de passe actuel"),
dbc.Input(
type="password",
@@ -74,19 +77,13 @@ def layout(error: str | None = None, password_changed: str | None = None, **_):
method="POST",
action="/auth/logout",
children=[
dcc.Input(type="hidden", id="csrf-logout", name="csrf_token"),
dcc.Input(
type="hidden",
id={"type": "csrf-input", "index": "logout"},
name="csrf_token",
),
dbc.Button("Déconnexion", type="submit", color="secondary"),
],
),
],
)
@callback(Output("csrf-change", "value"), Input("csrf-change", "id"))
def _fill_csrf_change(_):
return generate_csrf()
@callback(Output("csrf-logout", "value"), Input("csrf-logout", "id"))
def _fill_csrf_logout(_):
return generate_csrf()