Cześć wszystkim.
Od kilku dni męczę się z problemem dotyczącym keycloak.
Wcześniej moja aplikacja stała na JWT tokenie i tutaj wszystko działało tak jak trzeba.
Postanowiłem przejść na KeyCloak i tutaj pojawia się problem.
KeyCloak skonfigurowany, strzał na endpoint zwraca token, jednak gdy próbuję uwierzytelnić się tym tokenem w postmanie cały czas dostaję 401 unauthorized
Próbowałem już wszystkich możliwych sposobów, ale wciąż dostaję taki zwrot.
W klasie JwtAuthConverter dodałem sout'a zeby zobaczyć czy prawidłowo odczytuje z niego role i w konsoli dostaję zwrot: Resource roles: [client_admin]
czyli to czego oczekuję w WebSecurityConfigu (.hasAnyRoles("client_admin","client_user")
.
Znalazłem gdzieś, że może być konflikt, z powodu braku prefixu ROLE_
w roli, więc go dodaje w extractResourceRoles
, ale w dalszym ciągu nic to nie zmienia.
Nie mam już pomysłu, a myślę, że to jakaś pierdoła, która blokuje mnie żeby pójść dalej.
Będę bardzo wdzięczny za pomoc jakiejś mądrej głowy
Miłego weekendu!
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Value("${jwt.auth.converter.principleAttribute}")
private String principleAttributeName;
@Value("${jwt.auth.converter.resource-id}")
private String resourceId;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/auth/login").permitAll()
.requestMatchers("/currencies").permitAll()
.requestMatchers("/currencies/getRate/*").permitAll()
.requestMatchers("/currencies/exchange").hasAnyRole("client_user", "client_admin")
.requestMatchers("/currencies/exchangeAdmin").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthConverter())
.jwkSetUri("http://localhost:8080/realms/exchange-api/protocol/openid-connect/certs")
)
)
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return httpSecurity.build();
}
@Bean
public Converter<Jwt, AbstractAuthenticationToken> jwtAuthConverter() {
return new JwtAuthConverter();
}
public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> {
private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
@Override
public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
Collection<GrantedAuthority> authorities = Stream.concat(
jwtGrantedAuthoritiesConverter.convert(jwt).stream(),
extractResourceRoles(jwt).stream()
).collect(Collectors.toSet());
return new JwtAuthenticationToken(jwt, authorities, getPrincipleClaimName(jwt));
}
private String getPrincipleClaimName(Jwt jwt) {
String claimName = JwtClaimNames.SUB;
if (principleAttributeName != null) {
claimName = principleAttributeName;
}
return jwt.getClaim(claimName);
}
private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
Map<String, Object> resourceAccess;
Map<String, Object> resource;
Collection<String> resourceRoles;
if (jwt.getClaim("resource_access") == null) {
return Set.of();
}
resourceAccess = jwt.getClaim("resource_access");
if (resourceAccess.get(resourceId) == null) {
return Set.of();
}
resource = (Map<String, Object>) resourceAccess.get(resourceId);
resourceRoles = (Collection<String>) resource.get("roles");
System.out.println("Resource roles: " + resourceRoles);
return resourceRoles.stream()
.map(role -> "ROLE_" + role)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toSet());
}
}
}
`(.hasAnyRoles("client_admin","client_user")`
, zamiast w pogrubienie/pochylenie.