diff --git a/src/main/java/dev/lions/btpxpress/view/UserSessionBean.java b/src/main/java/dev/lions/btpxpress/view/UserSessionBean.java index 7c09e86..2c33183 100644 --- a/src/main/java/dev/lions/btpxpress/view/UserSessionBean.java +++ b/src/main/java/dev/lions/btpxpress/view/UserSessionBean.java @@ -24,8 +24,6 @@ import java.io.Serializable; */ @Named("userSession") @SessionScoped -@Getter -@Setter @Slf4j public class UserSessionBean implements Serializable { @@ -38,75 +36,80 @@ public class UserSessionBean implements Serializable { @IdToken JsonWebToken idToken; - private String nomComplet; - private String email; - private String avatarUrl; - private String role; - private int nombreNotificationsNonLues; - private int nombreMessagesNonLus; - /** - * Initialise les données de l'utilisateur connecté depuis le token OIDC. + * Récupère le nom complet de l'utilisateur depuis le token OIDC. + * Méthode dynamique qui récupère les informations à chaque appel. */ - @PostConstruct - public void init() { + public String getNomComplet() { try { - // Récupération depuis le token OIDC/JWT - if (securityIdentity != null && securityIdentity.getPrincipal() != null) { - log.info("Initialisation des informations utilisateur depuis OIDC"); - + if (securityIdentity != null && securityIdentity.getPrincipal() != null && idToken != null) { // Nom complet (preferred_username ou name) - nomComplet = idToken.getClaim("name"); - if (nomComplet == null || nomComplet.trim().isEmpty()) { - nomComplet = idToken.getClaim("preferred_username"); + String nom = idToken.getClaim("name"); + if (nom == null || nom.trim().isEmpty()) { + nom = idToken.getClaim("preferred_username"); } - if (nomComplet == null || nomComplet.trim().isEmpty()) { - nomComplet = securityIdentity.getPrincipal().getName(); + if (nom == null || nom.trim().isEmpty()) { + nom = securityIdentity.getPrincipal().getName(); } - - // Email - email = idToken.getClaim("email"); - - // Avatar par défaut - avatarUrl = "/resources/freya-layout/images/avatar-profilemenu.png"; - - // Rôles (premier rôle trouvé) - if (securityIdentity.getRoles() != null && !securityIdentity.getRoles().isEmpty()) { - role = securityIdentity.getRoles().iterator().next(); - // Formatage du rôle pour affichage (enlever préfixes) - role = role.replace("_", " ").replace("-", " "); - role = capitalizeWords(role); - } else { - role = "Utilisateur"; - } - - log.info("Utilisateur connecté: {} ({})", nomComplet, email); - - } else { - log.warn("SecurityIdentity non disponible, utilisation des valeurs par défaut"); - setDefaultValues(); + return nom != null ? nom : "Utilisateur"; } - - // TODO: Récupérer le nombre réel de notifications et messages depuis l'API - nombreNotificationsNonLues = 0; - nombreMessagesNonLus = 0; - } catch (Exception e) { - log.error("Erreur lors de l'initialisation du UserSession", e); - setDefaultValues(); + log.error("Erreur lors de la récupération du nom complet", e); } + return "Utilisateur"; } /** - * Valeurs par défaut si OIDC non disponible. + * Récupère l'email de l'utilisateur depuis le token OIDC. */ - private void setDefaultValues() { - nomComplet = "Utilisateur"; - email = "utilisateur@btpxpress.com"; - avatarUrl = "/resources/freya-layout/images/avatar-profilemenu.png"; - role = "Utilisateur"; - nombreNotificationsNonLues = 0; - nombreMessagesNonLus = 0; + public String getEmail() { + try { + if (securityIdentity != null && securityIdentity.getPrincipal() != null && idToken != null) { + String email = idToken.getClaim("email"); + return email != null ? email : "utilisateur@btpxpress.com"; + } + } catch (Exception e) { + log.error("Erreur lors de la récupération de l'email", e); + } + return "utilisateur@btpxpress.com"; + } + + /** + * Retourne l'URL de l'avatar (par défaut). + */ + public String getAvatarUrl() { + return "/resources/freya-layout/images/avatar-profilemenu.png"; + } + + /** + * Récupère le rôle de l'utilisateur depuis SecurityIdentity. + */ + public String getRole() { + try { + if (securityIdentity != null && securityIdentity.getRoles() != null && !securityIdentity.getRoles().isEmpty()) { + String role = securityIdentity.getRoles().iterator().next(); + // Formatage du rôle pour affichage (enlever préfixes) + role = role.replace("_", " ").replace("-", " "); + return capitalizeWords(role); + } + } catch (Exception e) { + log.error("Erreur lors de la récupération du rôle", e); + } + return "Utilisateur"; + } + + /** + * Nombre de notifications non lues (TODO: implémenter via API). + */ + public int getNombreNotificationsNonLues() { + return 0; + } + + /** + * Nombre de messages non lus (TODO: implémenter via API). + */ + public int getNombreMessagesNonLus() { + return 0; } /** @@ -130,17 +133,18 @@ public class UserSessionBean implements Serializable { /** * Retourne les initiales de l'utilisateur pour l'avatar. - * + * * @return Les initiales (ex: "JD" pour "Jean Dupont") */ public String getInitiales() { + String nomComplet = getNomComplet(); if (nomComplet == null || nomComplet.trim().isEmpty()) { return "U"; } - + String[] parts = nomComplet.trim().split("\\s+"); if (parts.length >= 2) { - return String.valueOf(parts[0].charAt(0)).toUpperCase() + + return String.valueOf(parts[0].charAt(0)).toUpperCase() + String.valueOf(parts[1].charAt(0)).toUpperCase(); } else if (parts.length == 1) { return parts[0].substring(0, Math.min(2, parts[0].length())).toUpperCase(); @@ -150,21 +154,44 @@ public class UserSessionBean implements Serializable { /** * Action de déconnexion OIDC/Keycloak. + * Redirige vers l'endpoint de logout Keycloak pour détruire la session. * * @return Null pour déclencher une redirection externe */ public String deconnecter() { try { - log.info("Déconnexion de l'utilisateur: {}", nomComplet); - // La déconnexion OIDC est gérée automatiquement par Quarkus - // via le endpoint /q/oidc/logout - // Redirection vers le logout endpoint + log.info("Déconnexion de l'utilisateur: {}", getNomComplet()); + jakarta.faces.context.FacesContext facesContext = jakarta.faces.context.FacesContext.getCurrentInstance(); jakarta.faces.context.ExternalContext externalContext = facesContext.getExternalContext(); - // Rediriger vers l'endpoint de logout OIDC de Quarkus - String logoutUrl = externalContext.getRequestContextPath() + "/q/oidc/logout"; - externalContext.redirect(logoutUrl); + // Construction de l'URL de logout Keycloak + String keycloakLogoutUrl = "https://security.lions.dev/realms/btpxpress/protocol/openid-connect/logout"; + + // URL de redirection après logout + String baseUrl = externalContext.getRequestScheme() + "://" + + externalContext.getRequestServerName() + ":" + + externalContext.getRequestServerPort() + + externalContext.getRequestContextPath(); + + String postLogoutRedirectUri = baseUrl + "/"; + + // Construire l'URL complète avec les paramètres + StringBuilder logoutUrl = new StringBuilder(keycloakLogoutUrl); + logoutUrl.append("?post_logout_redirect_uri=").append(java.net.URLEncoder.encode(postLogoutRedirectUri, "UTF-8")); + + // Ajouter le id_token_hint si disponible + if (idToken != null && idToken.getRawToken() != null) { + logoutUrl.append("&id_token_hint=").append(java.net.URLEncoder.encode(idToken.getRawToken(), "UTF-8")); + } + + log.info("Redirection vers Keycloak logout: {}", keycloakLogoutUrl); + + // Invalider la session HTTP locale + externalContext.invalidateSession(); + + // Rediriger vers Keycloak logout + externalContext.redirect(logoutUrl.toString()); facesContext.responseComplete(); return null; diff --git a/src/main/resources/META-INF/resources/WEB-INF/topbar.xhtml b/src/main/resources/META-INF/resources/WEB-INF/topbar.xhtml index dbd1dab..4a35c09 100644 --- a/src/main/resources/META-INF/resources/WEB-INF/topbar.xhtml +++ b/src/main/resources/META-INF/resources/WEB-INF/topbar.xhtml @@ -107,10 +107,11 @@