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:
@@ -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";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user