1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package org.bremersee.web.reactive.function.client;
18  
19  import org.bremersee.security.authentication.AccessTokenProvider;
20  import org.bremersee.security.authentication.AccessTokenRetriever;
21  import org.bremersee.security.authentication.AccessTokenRetrieverProperties;
22  import org.bremersee.security.authentication.ReactiveAccessTokenProviders;
23  import org.springframework.http.HttpHeaders;
24  import org.springframework.lang.NonNull;
25  import org.springframework.util.Assert;
26  import org.springframework.util.StringUtils;
27  import org.springframework.web.reactive.function.client.ClientRequest;
28  import org.springframework.web.reactive.function.client.ClientResponse;
29  import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
30  import org.springframework.web.reactive.function.client.ExchangeFunction;
31  import reactor.core.publisher.Mono;
32  
33  
34  
35  
36  
37  
38  public class AccessTokenAppender implements ExchangeFilterFunction {
39  
40    private final AccessTokenProvider<Mono<String>> accessTokenProvider;
41  
42    
43  
44  
45  
46  
47    public AccessTokenAppender(AccessTokenProvider<Mono<String>> accessTokenProvider) {
48      Assert.notNull(accessTokenProvider, "Access token provider must be present.");
49      this.accessTokenProvider = accessTokenProvider;
50    }
51  
52    @NonNull
53    @Override
54    public Mono<ClientResponse> filter(@NonNull ClientRequest request, @NonNull ExchangeFunction next) {
55      return accessTokenProvider.getAccessToken()
56          .switchIfEmpty(Mono.just(""))
57          .flatMap(tokenValue -> exchangeWithToken(request, tokenValue, next));
58    }
59  
60    private Mono<ClientResponse> exchangeWithToken(
61        ClientRequest request,
62        String tokenValue,
63        ExchangeFunction next) {
64  
65      if (StringUtils.hasText(tokenValue)) {
66        return next.exchange(ClientRequest
67            .from(request)
68            .headers(headers -> headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + tokenValue))
69            .build());
70      } else {
71        return next.exchange(request);
72      }
73    }
74  
75    
76  
77  
78  
79  
80    public static AccessTokenAppender fromAuthentication() {
81      return new AccessTokenAppender(ReactiveAccessTokenProviders.fromAuthentication());
82    }
83  
84    
85  
86  
87  
88  
89  
90    @SuppressWarnings("unused")
91    public static AccessTokenAppender withAccessTokenRetriever(
92        final AccessTokenRetrieverProperties properties) {
93      return new AccessTokenAppender(
94          ReactiveAccessTokenProviders.withAccessTokenRetriever(properties));
95    }
96  
97    
98  
99  
100 
101 
102 
103 
104   public static AccessTokenAppender withAccessTokenRetriever(
105       final AccessTokenRetriever<Mono<String>> retriever,
106       final AccessTokenRetrieverProperties properties) {
107     return new AccessTokenAppender(
108         ReactiveAccessTokenProviders.withAccessTokenRetriever(retriever, properties));
109   }
110 
111 }