序
本文主要研究一下AsyncHttpClient的SignatureCalculator
SignatureCalculator
org/asynchttpclient/SignatureCalculator.java
代码语言:javascript复制/**
* Interface that allows injecting signature calculator into
* {@link RequestBuilder} so that signature calculation and inclusion can
* be added as a pluggable component.
*
* @since 1.1
*/
public interface SignatureCalculator {
/**
* Method called when {@link RequestBuilder#build} method is called.
* Should first calculate signature information and then modify request
* (using passed {@link RequestBuilder}) to add signature (usually as
* an HTTP header).
*
* @param requestBuilder builder that can be used to modify request, usually
* by adding header that includes calculated signature. Be sure NOT to
* call {@link RequestBuilder#build} since this will cause infinite recursion
* @param request Request that is being built; needed to access content to
* be signed
*/
void calculateAndAddSignature(Request request,
RequestBuilderBase<?> requestBuilder);
}
SignatureCalculator定义了calculateAndAddSignature接口,它首先计算签名,然后添加到requestBuilder
OAuthSignatureCalculator
org/asynchttpclient/oauth/OAuthSignatureCalculator.java
代码语言:javascript复制/**
* OAuth {@link SignatureCalculator} that delegates to {@link OAuthSignatureCalculatorInstance}s.
*/
public class OAuthSignatureCalculator implements SignatureCalculator {
private static final ThreadLocal<OAuthSignatureCalculatorInstance> INSTANCES = ThreadLocal.withInitial(() -> {
try {
return new OAuthSignatureCalculatorInstance();
} catch (NoSuchAlgorithmException e) {
throw new ExceptionInInitializerError(e);
}
});
private final ConsumerKey consumerAuth;
private final RequestToken userAuth;
/**
* @param consumerAuth Consumer key to use for signature calculation
* @param userAuth Request/access token to use for signature calculation
*/
public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) {
this.consumerAuth = consumerAuth;
this.userAuth = userAuth;
}
@Override
public void calculateAndAddSignature(Request request, RequestBuilderBase<?> requestBuilder) {
try {
INSTANCES.get().sign(consumerAuth, userAuth, request, requestBuilder);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("Failed to compute a valid key from consumer and user secrets", e);
}
}
}
OAuthSignatureCalculator实现了SignatureCalculator接口,其calculateAndAddSignature方法使用了OAuthSignatureCalculatorInstance的sign方法
sign
org/asynchttpclient/oauth/OAuthSignatureCalculatorInstance.java
代码语言:javascript复制 public void sign(ConsumerKey consumerAuth, RequestToken userAuth, Request request, RequestBuilderBase<?> requestBuilder) throws InvalidKeyException {
String nonce = generateNonce();
long timestamp = generateTimestamp();
sign(consumerAuth, userAuth, request, requestBuilder, timestamp, nonce);
}
void sign(ConsumerKey consumerAuth, RequestToken userAuth, Request request, RequestBuilderBase<?> requestBuilder, long timestamp, String nonce) throws InvalidKeyException {
String percentEncodedNonce = Utf8UrlEncoder.percentEncodeQueryElement(nonce);
String signature = calculateSignature(consumerAuth, userAuth, request, timestamp, percentEncodedNonce);
String headerValue = constructAuthHeader(consumerAuth, userAuth, signature, timestamp, percentEncodedNonce);
requestBuilder.setHeader(HttpHeaderNames.AUTHORIZATION, headerValue);
}
String calculateSignature(ConsumerKey consumerAuth, RequestToken userAuth, Request request, long oauthTimestamp, String percentEncodedNonce) throws InvalidKeyException {
StringBuilder sb = signatureBaseString(consumerAuth, userAuth, request, oauthTimestamp, percentEncodedNonce);
ByteBuffer rawBase = StringUtils.charSequence2ByteBuffer(sb, UTF_8);
byte[] rawSignature = digest(consumerAuth, userAuth, rawBase);
// and finally, base64 encoded... phew!
return Base64.encode(rawSignature);
}
OAuthSignatureCalculatorInstance的sign方法先生成nonce及timestamp,然后通过calculateSignature计算signature,再通过constructAuthHeader计算headerValue,最后设置到requestBuilder的名为authorization的header
executeSignatureCalculator
org/asynchttpclient/RequestBuilderBase.java
代码语言:javascript复制 private RequestBuilderBase<?> executeSignatureCalculator() {
if (signatureCalculator == null)
return this;
// build a first version of the request, without signatureCalculator in play
RequestBuilder rb = new RequestBuilder(this.method);
// make copy of mutable collections so we don't risk affecting
// original RequestBuilder
// call setFormParams first as it resets other fields
if (this.formParams != null)
rb.setFormParams(this.formParams);
if (this.headers != null)
rb.headers.add(this.headers);
if (this.cookies != null)
rb.setCookies(this.cookies);
if (this.bodyParts != null)
rb.setBodyParts(this.bodyParts);
// copy all other fields
// but rb.signatureCalculator, that's the whole point here
rb.uriEncoder = this.uriEncoder;
rb.queryParams = this.queryParams;
rb.uri = this.uri;
rb.address = this.address;
rb.localAddress = this.localAddress;
rb.byteData = this.byteData;
rb.compositeByteData = this.compositeByteData;
rb.stringData = this.stringData;
rb.byteBufferData = this.byteBufferData;
rb.streamData = this.streamData;
rb.bodyGenerator = this.bodyGenerator;
rb.virtualHost = this.virtualHost;
rb.proxyServer = this.proxyServer;
rb.realm = this.realm;
rb.file = this.file;
rb.followRedirect = this.followRedirect;
rb.requestTimeout = this.requestTimeout;
rb.rangeOffset = this.rangeOffset;
rb.charset = this.charset;
rb.channelPoolPartitioning = this.channelPoolPartitioning;
rb.nameResolver = this.nameResolver;
Request unsignedRequest = rb.build();
signatureCalculator.calculateAndAddSignature(unsignedRequest, rb);
return rb;
}
executeSignatureCalculator会执行signatureCalculator.calculateAndAddSignature(unsignedRequest, rb)
build
org/asynchttpclient/RequestBuilderBase.java
代码语言:javascript复制 public Request build() {
updateCharset();
RequestBuilderBase<?> rb = executeSignatureCalculator();
Uri finalUri = rb.computeUri();
// make copies of mutable internal collections
List<Cookie> cookiesCopy = rb.cookies == null ? Collections.emptyList() : new ArrayList<>(rb.cookies);
List<Param> formParamsCopy = rb.formParams == null ? Collections.emptyList() : new ArrayList<>(rb.formParams);
List<Part> bodyPartsCopy = rb.bodyParts == null ? Collections.emptyList() : new ArrayList<>(rb.bodyParts);
return new DefaultRequest(rb.method,
finalUri,
rb.address,
rb.localAddress,
rb.headers,
cookiesCopy,
rb.byteData,
rb.compositeByteData,
rb.stringData,
rb.byteBufferData,
rb.streamData,
rb.bodyGenerator,
formParamsCopy,
bodyPartsCopy,
rb.virtualHost,
rb.proxyServer,
rb.realm,
rb.file,
rb.followRedirect,
rb.requestTimeout,
rb.readTimeout,
rb.rangeOffset,
rb.charset,
rb.channelPoolPartitioning,
rb.nameResolver);
}
RequestBuilderBase的build方法会执行executeSignatureCalculator
小结
SignatureCalculator定义了calculateAndAddSignature接口,它首先计算签名,然后添加到requestBuilder;它有个实现类为OAuthSignatureCalculator;RequestBuilderBase的build方法会执行executeSignatureCalculator。