CustomJwtAuthenticationConverter.java
package com.tdmconsult.ete.configuration;
import com.google.common.collect.ImmutableList;
import com.tdmconsult.ete.configuration.CustomJwtAuthenticationToken.CustomUserPrincipal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
public class CustomJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
// use framework-default converter as starting point
private final JwtGrantedAuthoritiesConverter defaultAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
@Override
public AbstractAuthenticationToken convert(final Jwt jwt) {
Collection<GrantedAuthority> authorities = Objects.requireNonNull(
defaultAuthoritiesConverter.convert(jwt), "unexpected behavior");
authorities.addAll(extractRealmRoles(jwt));
authorities.addAll(extractClientRoles(jwt));
CustomUserPrincipal principal = new CustomUserPrincipal(
jwt.getSubject(), // "sub"
jwt.getClaimAsString("preferred_username"),
jwt.getClaimAsString("email"),
jwt.getClaimAsString("given_name"),
jwt.getClaimAsString("family_name"),
ImmutableList.copyOf(authorities)
);
return new CustomJwtAuthenticationToken(jwt, authorities, principal);
}
private Collection<GrantedAuthority> extractRealmRoles(final Jwt jwt) {
Map<String, Object> realmAccess = jwt.getClaim("realm_access");
if (realmAccess == null || !realmAccess.containsKey("roles")) {
return List.of(); // Keine Rollen vorhanden
}
// Extrahiert die Liste der Rollen-Strings
@SuppressWarnings("unchecked")
List<String> roles = (List<String>) realmAccess.get("roles");
return roles.stream()
.filter(roleName -> roleName.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
private Collection<GrantedAuthority> extractClientRoles(final Jwt jwt) {
Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
if (resourceAccess == null) {
return List.of();
}
List<GrantedAuthority> clientAuthorities = new ArrayList<>();
// Wir iterieren über alle Clients (z.B. "mein-vue-client", "account", etc.)
for (Map.Entry<String, Object> entry : resourceAccess.entrySet()) {
if (entry.getValue() instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> clientConfig = (Map<String, Object>) entry.getValue();
if (clientConfig.containsKey("roles") && clientConfig.get("roles") instanceof List) {
@SuppressWarnings("unchecked")
List<String> clientRoles = (List<String>) clientConfig.get("roles");
// Jede Client-Rolle wird flach als "ROLE_rollenname" hinzugefügt
clientRoles.stream()
.map(role -> new SimpleGrantedAuthority(entry.getKey() + ":" + role))
.forEach(clientAuthorities::add);
}
}
}
return clientAuthorities;
}
}