Flutter调用SageMaker API时Header签名验证失败(403错误)
Flutter中AWS请求签名不匹配导致SageMaker API返回403问题
我在Flutter中实现了AWS请求签名逻辑,调用SageMaker API时返回403状态码,响应提示计算的请求签名与提供的不匹配。
错误响应信息
{"message":"我们计算的请求签名与您提供的签名不匹配。请检查您的AWS秘密访问密钥和签名方法。有关详细信息,请查阅服务文档。
此请求的规范字符串应为"}
签名实现代码
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; }
问题排查与修复点
- 日期一致性问题:代码中两次调用
DateTime.now().toUtc()生成日期,极端情况会跨秒导致date和date2所属日期不一致。应先获取一次UTC时间再格式化:var utcNow = DateTime.now().toUtc(); var date = DateFormat("yyyyMMdd'T'HHmmss'Z'").format(utcNow); var date2 = DateFormat("yyyyMMdd").format(utcNow); - 请求体不必要的小写处理:对
param调用toLowerCase()会修改请求体内容,若SageMaker API期望原始参数格式,会导致请求体哈希与AWS计算值不匹配。应去掉该处理,直接使用json.encode(param)。 - Canonical URI错误:
canonicalUri应仅包含请求路径,而非完整endpoint URL。例如endpoint为https://runtime.sagemaker.us-east-1.amazonaws.com/endpoints/my-endpoint/invocations时,canonicalUri需设为/endpoints/my-endpoint/invocations。 - HMAC链式计算错误:中间密钥(
kDate、kRegion等)需基于原始字节传递,而非十六进制字符串。之前的.toString()会导致哈希计算错误,修正后代码如下:var kSecret = utf8.encode("AWS4$secretKey"); var kDate = Hmac(sha256, kSecret).convert(utf8.encode(date2)).bytes; var kRegion = Hmac(sha256, kDate).convert(utf8.encode(region)).bytes; var kService = Hmac(sha256, kRegion).convert(utf8.encode(service)).bytes; var kSigning = Hmac(sha256, kService).convert(utf8.encode("aws4_request")).bytes; var signature = Hmac(sha256, kSigning).convert(utf8.encode(stringToSign)).toString(); - 签名算法常量验证:确保
ApiConstants.hmacShaTypeString的值为AWS4-HMAC-SHA256,这是AWS签名v4的固定要求。
内容的提问来源于stack exchange,提问作者Muhammad Bilal
相关产品推荐
相关产品推荐

