fix: multi-sessions + système de toasts pour erreurs visibles
Sessions:
- Cookie pxp_refresh path: /api/auth/refresh → /api/auth/ pour être envoyé au logout
- Logout supprime uniquement le token de la session courante (via cookie hash)
si pas de cookie = fallback suppression globale (rétro-compat)
Toasts:
- Store Alpine.store('toasts') avec error/success/warn/info + auto-dismiss
- Conteneur #pxp-toasts injecté dans <body>, persiste à travers les navigations Swup
- fetchMe(): HTTP non-401 → toast explicite (ex: HTTP 404 backend down)
- tryRefresh(): session expirée → sessionStorage → toast orange sur la page login
- logout(): message "Déconnexion réussie" sur la page login
- proxmoxPage.action(): toast succès/erreur pour start/stop LXC
- profilePage.revokeSession(): toast confirmation révocation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
21e1e0ed1e
commit
dc0c67b89c
3 changed files with 151 additions and 11 deletions
|
|
@ -118,10 +118,11 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
|||
// Cookie httpOnly pour le refresh token
|
||||
// Secure=true si TLS direct ou si derrière un proxy (Traefik) qui a terminé TLS
|
||||
isHTTPS := r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
|
||||
// Path élargi à /api/auth/ pour que le cookie soit envoyé au logout aussi
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "pxp_refresh",
|
||||
Value: refreshToken,
|
||||
Path: "/api/auth/refresh",
|
||||
Path: "/api/auth/",
|
||||
HttpOnly: true,
|
||||
Secure: isHTTPS,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
|
|
@ -141,14 +142,22 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
}
|
||||
|
||||
// Logout invalide la session de l'utilisateur.
|
||||
// Logout invalide la session courante de l'utilisateur.
|
||||
// POST /api/auth/logout
|
||||
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
claims := GetClaims(r)
|
||||
|
||||
// Supprimer tous les refresh tokens de cet utilisateur
|
||||
if claims != nil {
|
||||
h.db.Exec(`DELETE FROM refresh_tokens WHERE user_id = ?`, claims.UserID)
|
||||
// Supprimer uniquement le token de CETTE session (via cookie pxp_refresh)
|
||||
// Le cookie a Path=/api/auth/ donc il est bien envoyé sur ce endpoint.
|
||||
if cookie, err := r.Cookie("pxp_refresh"); err == nil {
|
||||
tokenHash := hashToken(cookie.Value)
|
||||
h.db.Exec(`DELETE FROM refresh_tokens WHERE token_hash = ? AND user_id = ?`,
|
||||
tokenHash, claims.UserID)
|
||||
} else {
|
||||
// Pas de cookie (session dégradée ou ancien cookie path) → supprimer toutes les sessions
|
||||
h.db.Exec(`DELETE FROM refresh_tokens WHERE user_id = ?`, claims.UserID)
|
||||
}
|
||||
h.auditLogger.Log(&claims.UserID, claims.Username, "logout", "", nil, clientIP(r))
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +165,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
|||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "pxp_refresh",
|
||||
Value: "",
|
||||
Path: "/api/auth/refresh",
|
||||
Path: "/api/auth/",
|
||||
HttpOnly: true,
|
||||
Expires: time.Unix(0, 0),
|
||||
MaxAge: -1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue