Refactoring - Bonne version améliorée

This commit is contained in:
dahoud
2026-02-05 16:30:20 +00:00
parent dd4dbe111e
commit 2a794523b6
20 changed files with 2327 additions and 620 deletions

View File

@@ -1,6 +1,7 @@
package com.lions.dev.service;
import com.lions.dev.entity.users.Users;
import com.lions.dev.util.UserRoles;
import io.smallrye.jwt.build.Jwt;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -9,13 +10,24 @@ import org.jboss.logging.Logger;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
/**
* Service d'émission de JWT au login.
* Le token contient sub (userId), groups (rôle) et est signé avec la clé secrète configurée.
* La validation des tokens sur les requêtes est assurée par quarkus-smallrye-jwt
*
* Le token contient :
* - sub (subject) : userId de l'utilisateur
* - groups : rôles de l'utilisateur (pour @RolesAllowed)
* - iss (issuer) : "afterwork"
* - iat (issued at) : timestamp de création
* - exp (expiration) : timestamp d'expiration
*
* La validation des tokens est assurée automatiquement par SmallRye JWT
* lorsque les endpoints sont protégés avec @RolesAllowed.
*
* @since 2.0 - Implémentation sécurité JWT production-ready
*/
@ApplicationScoped
public class JwtService {
@@ -26,6 +38,9 @@ public class JwtService {
@ConfigProperty(name = "afterwork.jwt.secret", defaultValue = "afterwork-jwt-secret-min-32-bytes-for-hs256!")
String secret;
@ConfigProperty(name = "smallrye.jwt.new-token.lifespan", defaultValue = "86400")
long tokenLifespanSeconds;
/**
* Génère un JWT pour l'utilisateur authentifié.
*
@@ -36,18 +51,69 @@ public class JwtService {
if (user == null || user.getId() == null) {
throw new IllegalArgumentException("User et id obligatoires pour générer le JWT");
}
Set<String> groups = Set.of("user", user.getRole() != null ? user.getRole() : "USER");
// Construire les groupes (rôles) pour @RolesAllowed
Set<String> groups = buildGroups(user);
SecretKey key = secretKeyFromConfig();
String token = Jwt.claims()
.issuer(ISSUER)
.subject(user.getId().toString())
.groups(groups)
.issuedAt(java.time.Instant.now())
.expiresIn(Duration.ofSeconds(tokenLifespanSeconds))
.jws()
.algorithm(io.smallrye.jwt.algorithm.SignatureAlgorithm.HS256)
.sign(key);
LOG.debug("JWT généré pour l'utilisateur " + user.getId());
LOG.info("JWT généré pour l'utilisateur " + user.getId() + " avec rôles: " + groups);
return token;
}
/**
* Construit l'ensemble des groupes (rôles) pour le token JWT.
* Inclut le rôle principal et les rôles implicites selon la hiérarchie.
*
* Hiérarchie : SUPER_ADMIN > ADMIN > MANAGER > USER
*
* @param user L'utilisateur
* @return Set des groupes à inclure dans le token
*/
private Set<String> buildGroups(Users user) {
Set<String> groups = new HashSet<>();
String role = user.getRole() != null ? user.getRole().toUpperCase() : UserRoles.USER;
// Ajouter le rôle principal
groups.add(role);
// Ajouter les rôles implicites selon la hiérarchie
switch (role) {
case UserRoles.SUPER_ADMIN:
groups.add(UserRoles.ADMIN);
groups.add(UserRoles.MANAGER);
groups.add(UserRoles.USER);
break;
case UserRoles.ADMIN:
groups.add(UserRoles.MANAGER);
groups.add(UserRoles.USER);
break;
case UserRoles.MANAGER:
groups.add(UserRoles.USER);
break;
case UserRoles.USER:
default:
// USER n'a pas de rôles implicites supplémentaires
break;
}
return groups;
}
/**
* Crée la clé secrète à partir de la configuration.
* Assure que la clé fait au moins 32 bytes pour HS256.
*/
private SecretKey secretKeyFromConfig() {
byte[] decoded = secret.getBytes(StandardCharsets.UTF_8);
if (decoded.length < 32) {
@@ -58,3 +124,4 @@ public class JwtService {
return new SecretKeySpec(decoded, "HmacSHA256");
}
}