You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用OkHttp签名AWS API Gateway请求时遇「Missing Authentication Token」

解决Android中OkHttp签名AWS API Gateway报「Missing Authentication Token」的问题

嘿,我之前也碰到过一模一样的坑!Postman能用但自己写的Android代码就报这个错,大概率是签名过程中几个容易忽略的细节没处理到位,给你列几个排查和修复的方向:


1. 务必处理临时凭证的Session Token

Cognito返回的是临时安全凭证,除了AWSAccessKeyId和AWSSecretKey,你必须把SessionToken加到请求头的X-Amz-Security-Token里,而且这个头要被纳入签名计算的范围:

  • 生成签名时,SignedHeaders要包含x-amz-security-token(注意小写,AWS签名对大小写敏感)
  • 最终请求的头里必须带上这个Token,Postman会自动帮你处理,但手动写代码很容易漏

2. 核对请求路径和API Gateway配置完全匹配

这个是最容易踩的坑!API Gateway的路径是大小写敏感的,而且如果你的API配置了阶段前缀(比如/prod、/dev),代码里必须用完整路径:

  • 比如Postman里用的是https://xxx.execute-api.us-east-1.amazonaws.com/prod/my-endpoint,那代码里的请求路径不能只写/my-endpoint,必须带上/prod/my-endpoint
  • 哪怕路径差一个斜杠或者大小写不对,API Gateway都会直接返回「Missing Authentication Token」,因为它找不到对应的资源

3. 检查OkHttp拦截器的执行顺序和请求修改逻辑

如果用OkHttp的Interceptor处理签名,要注意:

  • 拦截器要在所有请求体、路径修改之后添加,否则签名计算的内容和实际请求不一致
  • 确保拦截器没有意外修改HTTP方法(比如把POST改成GET)、路径或者请求体内容
  • 打印拦截器处理前后的请求头和路径,对比Postman的请求细节

4. 确认时间同步和X-Amz-Date格式

AWS签名v4要求请求的X-Amz-Date和服务器UTC时间误差不能超过5分钟:

  • 必须用YYYYMMDD'T'HHMMSS'Z'格式的UTC时间(比如20240520T123456Z)
  • 不要用本地时间,否则时间差过大直接被拒绝

5. 对比Postman和Android请求的签名细节

把Postman导出的请求头(所有AWS相关头)和你代码里生成的做对比:

  • 检查Authorization头的格式:是否包含Credential、SignedHeaders、Signature三个部分
  • 核对SignedHeaders里的头列表是否和实际请求的头完全一致(要按字母排序)
  • 确认请求体的SHA256哈希计算正确:如果是POST请求,要计算请求体的哈希;如果是空请求体,要用固定的空哈希值e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

给你一个简化的OkHttp签名拦截器示例

核心逻辑要确保覆盖所有必要的签名步骤:

public class AwsApiSigningInterceptor implements Interceptor {
    private final AwsCredentials credentials;
    private final String service = "execute-api";
    private final String region = "us-east-1"; // 替换成你的API区域

    public AwsApiSigningInterceptor(AwsCredentials credentials) {
        this.credentials = credentials;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        ZonedDateTime utcNow = ZonedDateTime.now(ZoneOffset.UTC);
        String amzDate = utcNow.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
        String dateStamp = utcNow.format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        // 1. 构建规范请求
        String canonicalRequest = buildCanonicalRequest(original, amzDate);
        // 2. 构建待签名字符串
        String credentialScope = dateStamp + "/" + region + "/" + service + "/aws4_request";
        String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" + hashSha256(canonicalRequest);
        // 3. 计算签名
        String signature = calculateSignature(stringToSign, credentials.getAWSSecretKey(), dateStamp, region, service);
        // 4. 构建授权头
        String authHeader = String.format(
                "AWS4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s",
                credentials.getAWSAccessKeyId(),
                credentialScope,
                getSignedHeaders(original),
                signature
        );

        // 5. 构建带签名的请求
        Request signedRequest = original.newBuilder()
                .header("X-Amz-Date", amzDate)
                .header("X-Amz-Security-Token", credentials.getSessionToken())
                .header("Authorization", authHeader)
                .build();

        return chain.proceed(signedRequest);
    }

    // 辅助方法:构建规范请求(省略实现,需处理方法、路径、查询参数、头、请求体哈希)
    private String buildCanonicalRequest(Request request, String amzDate) { /* ... */ }
    // 辅助方法:计算SHA256哈希
    private String hashSha256(String input) { /* ... */ }
    // 辅助方法:获取排序后的签名头列表
    private String getSignedHeaders(Request request) { /* ... */ }
    // 辅助方法:计算HMAC-SHA256签名
    private String calculateSignature(String stringToSign, String secretKey, String dateStamp, String region, String service) { /* ... */ }
}

我当时是因为代码里漏加了API的阶段前缀,补上之后就立刻正常了,你可以先排查这个点,再逐步检查其他细节!

内容的提问来源于stack exchange,提问作者Clive Sargeant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:34:34