feat: Affichage des informations utilisateur réelles depuis OIDC

Implémentation de l'extraction des informations utilisateur réelles
depuis les JWT tokens Keycloak au lieu des données fictives.

Modifications:
- UserSessionBean: Injection SecurityIdentity et IdToken
- Extraction dynamique: nom, email, rôles depuis JWT claims
- Logout via endpoint Quarkus OIDC (/q/oidc/logout)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
dahoud
2025-11-08 22:56:12 +00:00
parent 99bf1be24e
commit df0243d4f8
2 changed files with 113 additions and 15 deletions

View File

@@ -1,19 +1,24 @@
package dev.lions.btpxpress.view;
import io.quarkus.oidc.IdToken;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.jwt.JsonWebToken;
import java.io.Serializable;
/**
* Bean de session pour gérer les informations de l'utilisateur connecté.
*
*
* <p>Ce bean stocke les informations de session de l'utilisateur authentifié,
* telles que le nom, l'email, l'avatar, et les statistiques rapides.</p>
*
*
* @author BTP Xpress Team
* @version 1.0
*/
@@ -21,10 +26,18 @@ import java.io.Serializable;
@SessionScoped
@Getter
@Setter
@Slf4j
public class UserSessionBean implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
SecurityIdentity securityIdentity;
@Inject
@IdToken
JsonWebToken idToken;
private String nomComplet;
private String email;
private String avatarUrl;
@@ -33,17 +46,86 @@ public class UserSessionBean implements Serializable {
private int nombreMessagesNonLus;
/**
* Initialise les données de l'utilisateur connecté.
* Initialise les données de l'utilisateur connecté depuis le token OIDC.
*/
@PostConstruct
public void init() {
// TODO: Récupérer depuis le token JWT ou la session OIDC
nomComplet = "Jean Dupont";
email = "jean.dupont@btpxpress.com";
try {
// Récupération depuis le token OIDC/JWT
if (securityIdentity != null && securityIdentity.getPrincipal() != null) {
log.info("Initialisation des informations utilisateur depuis OIDC");
// Nom complet (preferred_username ou name)
nomComplet = idToken.getClaim("name");
if (nomComplet == null || nomComplet.trim().isEmpty()) {
nomComplet = idToken.getClaim("preferred_username");
}
if (nomComplet == null || nomComplet.trim().isEmpty()) {
nomComplet = 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();
}
// 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();
}
}
/**
* Valeurs par défaut si OIDC non disponible.
*/
private void setDefaultValues() {
nomComplet = "Utilisateur";
email = "utilisateur@btpxpress.com";
avatarUrl = "/resources/freya-layout/images/avatar-profilemenu.png";
role = "Gestionnaire de Projets";
nombreNotificationsNonLues = 5;
nombreMessagesNonLus = 3;
role = "Utilisateur";
nombreNotificationsNonLues = 0;
nombreMessagesNonLus = 0;
}
/**
* Capitalize first letter of each word.
*/
private String capitalizeWords(String str) {
if (str == null || str.isEmpty()) {
return str;
}
String[] words = str.toLowerCase().split(" ");
StringBuilder result = new StringBuilder();
for (String word : words) {
if (!word.isEmpty()) {
result.append(Character.toUpperCase(word.charAt(0)))
.append(word.substring(1))
.append(" ");
}
}
return result.toString().trim();
}
/**
@@ -67,13 +149,29 @@ public class UserSessionBean implements Serializable {
}
/**
* Action de déconnexion.
*
* @return La page de login
* Action de déconnexion OIDC/Keycloak.
*
* @return Null pour déclencher une redirection externe
*/
public String deconnecter() {
// TODO: Implémenter la déconnexion OIDC/Keycloak
return "/login?faces-redirect=true";
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
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);
facesContext.responseComplete();
return null;
} catch (Exception e) {
log.error("Erreur lors de la déconnexion", e);
return "/login?faces-redirect=true";
}
}
}

View File

@@ -15,7 +15,7 @@ jakarta.faces.VALIDATE_EMPTY_FIELDS=auto
quarkus.arc.remove-unused-beans=false
quarkus.http.port=8081
quarkus.http.port=8080
quarkus.http.cors=true
quarkus.http.cors.origins=http://localhost:8080,https://security.lions.dev