Cache the encoded credentials in BasicAuthenticationInterceptor
Prior to this commit, the Basic Authentication credentials were encoded for each request. This commit addresses this minor performance issue by caching the encoded credentials in BasicAuthenticationInterceptor. In addition, this commit introduces new encodeBasicAuth() and setBasicAuth(String encodedCredentials) methods in HttpHeaders to support this feature. Closes gh-23204
This commit is contained in:
parent
5008423408
commit
3e41f5e6b6
|
@ -742,7 +742,9 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
* @throws IllegalArgumentException if either {@code user} or
|
||||
* {@code password} contain characters that cannot be encoded to ISO-8859-1
|
||||
* @since 5.1
|
||||
* @see #setBasicAuth(String)
|
||||
* @see #setBasicAuth(String, String, Charset)
|
||||
* @see #encodeBasicAuth(String, String, Charset)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
public void setBasicAuth(String username, String password) {
|
||||
|
@ -759,24 +761,33 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
* @throws IllegalArgumentException if {@code username} or {@code password}
|
||||
* contains characters that cannot be encoded to the given charset
|
||||
* @since 5.1
|
||||
* @see #setBasicAuth(String)
|
||||
* @see #setBasicAuth(String, String)
|
||||
* @see #encodeBasicAuth(String, String, Charset)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
public void setBasicAuth(String username, String password, @Nullable Charset charset) {
|
||||
Assert.notNull(username, "Username must not be null");
|
||||
Assert.notNull(password, "Password must not be null");
|
||||
if (charset == null) {
|
||||
charset = StandardCharsets.ISO_8859_1;
|
||||
}
|
||||
setBasicAuth(encodeBasicAuth(username, password, charset));
|
||||
}
|
||||
|
||||
CharsetEncoder encoder = charset.newEncoder();
|
||||
if (!encoder.canEncode(username) || !encoder.canEncode(password)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Username or password contains characters that cannot be encoded to " + charset.displayName());
|
||||
}
|
||||
|
||||
String credentialsString = username + ":" + password;
|
||||
byte[] encodedBytes = Base64.getEncoder().encode(credentialsString.getBytes(charset));
|
||||
String encodedCredentials = new String(encodedBytes, charset);
|
||||
/**
|
||||
* Set the value of the {@linkplain #AUTHORIZATION Authorization} header to
|
||||
* Basic Authentication based on the given {@linkplain #encodeBasicAuth
|
||||
* encoded credentials}.
|
||||
* <p>Favor this method over {@link #setBasicAuth(String, String)} and
|
||||
* {@link #setBasicAuth(String, String, Charset)} if you wish to cache the
|
||||
* encoded credentials.
|
||||
* @param encodedCredentials the encoded credentials
|
||||
* @throws IllegalArgumentException if supplied credentials string is
|
||||
* {@code null} or blank
|
||||
* @since 5.2
|
||||
* @see #setBasicAuth(String, String)
|
||||
* @see #setBasicAuth(String, String, Charset)
|
||||
* @see #encodeBasicAuth(String, String, Charset)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
public void setBasicAuth(String encodedCredentials) {
|
||||
Assert.hasText(encodedCredentials, "'encodedCredentials' must not be null or blank");
|
||||
set(AUTHORIZATION, "Basic " + encodedCredentials);
|
||||
}
|
||||
|
||||
|
@ -1781,6 +1792,41 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
.collect(Collectors.joining(", ", "[", "]"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given username and password into Basic Authentication credentials.
|
||||
* <p>The encoded credentials returned by this method can be supplied to
|
||||
* {@link #setBasicAuth(String)} to set the Basic Authentication header.
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @param charset the charset to use to convert the credentials into an octet
|
||||
* sequence. Defaults to {@linkplain StandardCharsets#ISO_8859_1 ISO-8859-1}.
|
||||
* @throws IllegalArgumentException if {@code username} or {@code password}
|
||||
* contains characters that cannot be encoded to the given charset
|
||||
* @since 5.2
|
||||
* @see #setBasicAuth(String)
|
||||
* @see #setBasicAuth(String, String)
|
||||
* @see #setBasicAuth(String, String, Charset)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
public static String encodeBasicAuth(String username, String password, @Nullable Charset charset) {
|
||||
Assert.notNull(username, "Username must not be null");
|
||||
Assert.doesNotContain(username, ":", "Username must not contain a colon");
|
||||
Assert.notNull(password, "Password must not be null");
|
||||
if (charset == null) {
|
||||
charset = StandardCharsets.ISO_8859_1;
|
||||
}
|
||||
|
||||
CharsetEncoder encoder = charset.newEncoder();
|
||||
if (!encoder.canEncode(username) || !encoder.canEncode(password)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Username or password contains characters that cannot be encoded to " + charset.displayName());
|
||||
}
|
||||
|
||||
String credentialsString = username + ":" + password;
|
||||
byte[] encodedBytes = Base64.getEncoder().encode(credentialsString.getBytes(charset));
|
||||
return new String(encodedBytes, charset);
|
||||
}
|
||||
|
||||
// Package-private: used in ResponseCookie
|
||||
static String formatDate(long date) {
|
||||
Instant instant = Instant.ofEpochMilli(date);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -25,25 +25,21 @@ import org.springframework.http.client.ClientHttpRequestExecution;
|
|||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequestInterceptor} to apply a given HTTP Basic Authentication
|
||||
* username/password pair, unless a custom Authorization header has been set before.
|
||||
* username/password pair, unless a custom {@code Authorization} header has
|
||||
* already been set.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 5.1.1
|
||||
* @see HttpHeaders#setBasicAuth
|
||||
* @see HttpHeaders#AUTHORIZATION
|
||||
*/
|
||||
public class BasicAuthenticationInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String password;
|
||||
|
||||
@Nullable
|
||||
private final Charset charset;
|
||||
private final String encodedCredentials;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -52,6 +48,7 @@ public class BasicAuthenticationInterceptor implements ClientHttpRequestIntercep
|
|||
* @param username the username to use
|
||||
* @param password the password to use
|
||||
* @see HttpHeaders#setBasicAuth(String, String)
|
||||
* @see HttpHeaders#encodeBasicAuth(String, String, Charset)
|
||||
*/
|
||||
public BasicAuthenticationInterceptor(String username, String password) {
|
||||
this(username, password, null);
|
||||
|
@ -64,12 +61,10 @@ public class BasicAuthenticationInterceptor implements ClientHttpRequestIntercep
|
|||
* @param password the password to use
|
||||
* @param charset the charset to use
|
||||
* @see HttpHeaders#setBasicAuth(String, String, Charset)
|
||||
* @see HttpHeaders#encodeBasicAuth(String, String, Charset)
|
||||
*/
|
||||
public BasicAuthenticationInterceptor(String username, String password, @Nullable Charset charset) {
|
||||
Assert.doesNotContain(username, ":", "Username must not contain a colon");
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.charset = charset;
|
||||
this.encodedCredentials = HttpHeaders.encodeBasicAuth(username, password, charset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,7 +74,7 @@ public class BasicAuthenticationInterceptor implements ClientHttpRequestIntercep
|
|||
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
|
||||
headers.setBasicAuth(this.username, this.password, this.charset);
|
||||
headers.setBasicAuth(this.encodedCredentials);
|
||||
}
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue