前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊AsyncHttpClient的SignatureCalculator

聊聊AsyncHttpClient的SignatureCalculator

作者头像
code4it
发布2023-12-19 17:19:56
1370
发布2023-12-19 17:19:56
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下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。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SignatureCalculator
  • OAuthSignatureCalculator
  • sign
  • executeSignatureCalculator
  • build
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档