Search code examples
spring-webfluxspring-security-oauth2spring-oauth2

How to extract accountId from oauth2 token in webfilter


Im using webflux in my program and oauth2 security (keycloack as UAA server) I want to extract some information from oauth2 jwt and I do it well . but i need to get some information in filter . when I use my old method it not work in filter (WebFilter) . Is there any way to parse token and get information from it ? Is my way correct or I should extract it using springSecurityFilterChain instead of WebFilter? I want check accountId in token with accountId in url that client send using filter.

Hear is my code to extract accountId it not work in WebFilter but it work when i use it services or controller

  public class SecurityFilter implements WebFilter {
    
    
        @Override
        public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
           ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication).map(Principal::getName).filter((accountId) -> accountId.equals(clientAccountId)

.switchIfEmpty(Mono.error(new SystemException("401 ERROR")));;
          return webFilterChain.filter(serverWebExchange);
    
    }

Hear is my second way to extract accountId :

public class SecurityFilter implements WebFilter {


    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
      serverWebExchange.getPrincipal().map(Principal::getName).filter((accountId) -> accountId.equals(clientAccountId). .switchIfEmpty(Mono.error(new SystemException("401 ERROR")));;
      return webFilterChain.filter(serverWebExchange);

}

and my security config is :

 @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange()
                .pathMatchers("/api/**").authenticated()
              //  .pathMatchers("/**").permitAll()
                .anyExchange().authenticated()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))
                .and()
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
        return http.build();
    }
     

I think i should have another SecurityWebFilterChain method that do this for me ??


Solution

  • You are looking for smth like this

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        var clientAccountId = "clientId";
        return exchange.getPrincipal()
                .map(Principal::getName)
                .flatMap((accountId) -> {
                    if (accountId.equals(clientAccountId) && exchange.getRequest().getPath().value().equals("/my/api")) {
                        return Mono.just(accountId);
                    }
                    return Mono.error(new IllegalArgumentException("401 ERROR"));
                })
                .flatMap(tokenJwt -> chain.filter(exchange))
                .onErrorResume(r -> {
                    exchange.getResponse().setRawStatusCode(HttpStatus.UNAUTHORIZED.value());
                    return exchange.getResponse().setComplete();
                });
    }
    

    Note: that when you are using reactive then until you or spring subscribe to it it wont be executed.