KeycloakJwtGrantedAuthoritiesConverter.java
package io.github.nikoir.expensetracker.security;
import io.github.nikoir.expensetracker.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Component
@RequiredArgsConstructor
public class KeycloakJwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
//TODO: сделать лучше, security-слой не должен знать о слое бизнес-логики
private final UserService userService;
@Override
public Collection<GrantedAuthority> convert(Jwt source) {
//1. Создаем пользователя, если его нет в базе
userService.createUserIfNotExists(source.getSubject());
// 1. Извлекаем realm roles
Collection<GrantedAuthority> realmRoles = extractRoles(source);
// 2. Извлекаем resource roles (из account)
Collection<GrantedAuthority> resourceRoles = extractResourceRoles(source);
// 3. Извлекаем scopes
Collection<GrantedAuthority> scopes = extractScopes(source);
// 4. Объединяем все authorities
return Stream.of(realmRoles, resourceRoles, scopes)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
private Collection<GrantedAuthority> extractRoles(Jwt jwt) {
Map<String, Object> realmAccess = jwt.getClaim("realm_access");
if (realmAccess == null) {
return Collections.emptyList();
}
List<String> roles = (List<String>) realmAccess.get("roles");
if (roles == null) {
return Collections.emptyList();
}
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
private Collection<GrantedAuthority> extractResourceRoles(Jwt jwt) {
Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
if (resourceAccess == null) {
return Collections.emptyList();
}
Map<String, Object> resource = (Map<String, Object>) resourceAccess.get("account");
if (resource == null) {
return Collections.emptyList();
}
List<String> roles = (List<String>) resource.get("roles");
if (roles == null) {
return Collections.emptyList();
}
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
private Collection<GrantedAuthority> extractScopes(Jwt jwt) {
String scope = jwt.getClaim("scope");
if (scope == null) {
return Collections.emptyList();
}
return Arrays.stream(scope.split(" "))
.map(scopeName -> new SimpleGrantedAuthority("SCOPE_" + scopeName))
.collect(Collectors.toList());
}
}