Flutter调用AWS SageMaker API遇403签名不匹配问题求助
AWS SageMaker API签名错误(403)排查
调用AWS SageMaker API时返回403状态码,响应提示:
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been"}
以下是签名生成代码:
Map<String, String> signRequest(String param) { var method = "POST"; var uri = endpoint; var secretKey = secretKey; var accessKey = accessKey; var region = awsRegion; var service = serviceType; var host = baseUrl; var date = DateFormat("yyyyMMdd'T'HHmmss'Z'").format(DateTime.now().toUtc()); var date2 = DateFormat("yyyyMMdd").format(DateTime.now().toUtc()); var requestBody = utf8.encode(json.encode(param.toLowerCase())); var hashedPayloads = sha256.convert(requestBody).toString().toLowerCase(); var canonicalUri = uri; var canonicalQuerystring = ""; var canonicalHeaders = "content-type:application/json\nhost:$host\nx-amz-content-sha256:$hashedPayloads\nx-amz-date:$date\n"; var signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date"; var canonicalRequest = "$method\n$canonicalUri\n$canonicalQuerystring\n$canonicalHeaders\n$signedHeaders\n$hashedPayloads"; var credentialScope = "$date2/$region/$service/aws4_request"; var stringToSign = "${ApiConstants.hmacShaTypeString}\n$date\n$credentialScope\n${sha256.convert(utf8.encode(canonicalRequest))}"; var kSecret = "AWS4$secretKey"; var kDate = Hmac(sha256, utf8.encode(kSecret)) .convert(utf8.encode(date2)) .toString(); var kRegion = Hmac(sha256, utf8.encode(kDate)) .convert(utf8.encode(region)) .toString(); var kService = Hmac(sha256, utf8.encode(kRegion)) .convert(utf8.encode(service)) .toString(); var kSigning = Hmac(sha256, utf8.encode(kService)) .convert(utf8.encode("aws4_request")) .toString(); var signature = Hmac(sha256, utf8.encode(kSigning)) .convert(utf8.encode(stringToSign)) .toString(); var authorizationHeader = "${ApiConstants.hmacShaTypeString} Credential=$accessKey/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature"; Map<String, String> headers = { "Content-Type": "application/json", "X-Amz-Date": date, "X-Amz-Content-Sha256": hashedPayloads, "Authorization": authorizationHeader }; return headers; }
排查出的问题点:
- 请求体篡改:代码中对
param调用了toLowerCase(),导致序列化后的请求体与实际发送内容不一致,哈希值不匹配。删除param.toLowerCase(),直接使用原始参数序列化。 - HMAC结果转换错误:所有HMAC计算后的
.toString()会返回带格式的字符串(如SHA256(...)),而非纯十六进制哈希值。需要将HMAC的字节结果转换为小写十六进制字符串,可添加辅助函数:
替换所有HMAC转换代码,比如:String bytesToHex(Uint8List bytes) { return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join().toLowerCase(); }var kDate = bytesToHex(Hmac(sha256, utf8.encode(kSecret)).convert(utf8.encode(date2)).bytes); - Canonical URI错误:
canonicalUri必须是请求的路径部分,不能包含协议、主机。检查endpoint变量是否仅存储路径(如/endpoints/my-endpoint/invocations),而非完整URL。 - 时间不一致:两次调用
DateTime.now().toUtc()可能导致微妙级时间差,应先获取一次UTC时间再格式化:final utcNow = DateTime.now().toUtc(); final date = DateFormat("yyyyMMdd'T'HHmmss'Z'").format(utcNow); final date2 = DateFormat("yyyyMMdd").format(utcNow); - Host头匹配问题:确保
host变量与实际请求的主机完全一致(小写,无协议、路径),比如runtime.sagemaker.us-east-1.amazonaws.com。
内容的提问来源于stack exchange,提问作者Muhammad Bilal
相关产品推荐
相关产品推荐

