I am having Spring Cloud Gateway with a custom filter. In this filter, I try to call my webclient with a parameter. The roles from the ReactiveSecurityContextHolder. The getAccessToken result a
com.xy.HeaderGatewayFilter$apply$1$1.apply(HeaderGatewayFilter.kt:37).
If I just return "getAccessToken(webClient, "fixString" ).flatMap(chain::filter)" without the actual roles its working and returns an accessToken.
@Component
class HeaderGatewayFilter(@Autowired private val webClient: WebClient) : AbstractGatewayFilterFactory<HeaderGatewayFilter.Config>() {
open class Config
override fun apply(config: Config?): GatewayFilter {
return OrderedGatewayFilter( { exchange, chain ->
return@OrderedGatewayFilter getCurrentUserRole()
.map{rolle -> getAccessToken(webClient, rolle )
}
.map { accessToken ->
exchange.request
.mutate()
.header(HttpHeaders.AUTHORIZATION, "Bearer ${accessToken}")
return@map exchange
}.flatMap(chain::filter)
},40)
fun getAccessToken(webClient: WebClient, rolle: String): Mono<String> {
val map: MultiValueMap<String, String> = LinkedMultiValueMap()
map.add("scope", "role:${rolle}")
val inserter = BodyInserters.fromFormData(map)
return webClient.post().body(inserter).retrieve().bodyToMono(Map::class.java).map {
it["access_token"] as String }
}
fun getCurrentUserRole() : Mono<String> {
return ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(IllegalStateException("Context is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getPrincipal)
.cast(Jwt::class.java)
.map {jwt ->
return@map jwt.claims["realm_access"] as JSONObject
}
.map { realmAccess ->
return@map realmAccess["roles"] as JSONArray}
.map { rollen -> rollen.first().toString() }
}
Ok, i got it. Everything in my cascade has to return a Mono. I had a mapping, which returned a String, but now i changed it to Mono