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,10 +1,15 @@
package dev.lions.btpxpress.view; package dev.lions.btpxpress.view;
import io.quarkus.oidc.IdToken;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.jwt.JsonWebToken;
import java.io.Serializable; import java.io.Serializable;
@@ -21,10 +26,18 @@ import java.io.Serializable;
@SessionScoped @SessionScoped
@Getter @Getter
@Setter @Setter
@Slf4j
public class UserSessionBean implements Serializable { public class UserSessionBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Inject
SecurityIdentity securityIdentity;
@Inject
@IdToken
JsonWebToken idToken;
private String nomComplet; private String nomComplet;
private String email; private String email;
private String avatarUrl; private String avatarUrl;
@@ -33,17 +46,86 @@ public class UserSessionBean implements Serializable {
private int nombreMessagesNonLus; private int nombreMessagesNonLus;
/** /**
* Initialise les données de l'utilisateur connecté. * Initialise les données de l'utilisateur connecté depuis le token OIDC.
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
// TODO: Récupérer depuis le token JWT ou la session OIDC try {
nomComplet = "Jean Dupont"; // Récupération depuis le token OIDC/JWT
email = "jean.dupont@btpxpress.com"; 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"; avatarUrl = "/resources/freya-layout/images/avatar-profilemenu.png";
role = "Gestionnaire de Projets";
nombreNotificationsNonLues = 5; // Rôles (premier rôle trouvé)
nombreMessagesNonLus = 3; 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 = "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. * Action de déconnexion OIDC/Keycloak.
* *
* @return La page de login * @return Null pour déclencher une redirection externe
*/ */
public String deconnecter() { public String deconnecter() {
// TODO: Implémenter la déconnexion OIDC/Keycloak 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"; return "/login?faces-redirect=true";
} }
}
} }

View File

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