View Javadoc
1   /*
2    * Copyright 2019 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * The access token appender.
35   *
36   * @author Christian Bremer
37   */
38  public class AccessTokenAppender implements ExchangeFilterFunction {
39  
40    private final AccessTokenProvider<Mono<String>> accessTokenProvider;
41  
42    /**
43     * Instantiates a new access token appender.
44     *
45     * @param accessTokenProvider the access token provider
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     * From authentication access token appender.
77     *
78     * @return the access token appender
79     */
80    public static AccessTokenAppender fromAuthentication() {
81      return new AccessTokenAppender(ReactiveAccessTokenProviders.fromAuthentication());
82    }
83  
84    /**
85     * With access token retriever access token appender.
86     *
87     * @param properties the properties
88     * @return the access token appender
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     * With access token retriever access token appender.
99     *
100    * @param retriever the retriever
101    * @param properties the properties
102    * @return the access token appender
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 }