使用aws-sdk-js调用CognitoSync时触发InvalidSignatureException错误
解决CognitoSync调用的InvalidSignatureException问题
从你的描述和请求细节来看,核心问题出在本地代理xhr_proxy对CognitoSync请求URL的重复编码,导致AWS服务端验证签名时不匹配,而DynamoDB请求因为是POST方式,签名逻辑受URL影响较小,所以能正常工作。
问题分析
对比成功的DynamoDB请求和失败的CognitoSync请求:
- CognitoSync是GET请求,签名计算依赖完整的URL路径。你的请求URL中,IdentityPoolId和IdentityId里的冒号(
:)被重复编码了:原本的us-east-1:2bc13d33-xxx变成了us-east-1%253A2bc13d33-xxx(%3A是冒号的一次编码,%253A是对%3A再次编码的结果)。 - AWS签名V4要求URL路径使用规范的编码方式,重复编码的路径会被服务端视为完全不同的请求,因此计算出的签名和你发送的签名不匹配,返回403错误。
- DynamoDB是POST请求,签名主要基于请求体和请求头,URL的影响有限,所以没有触发这个问题。
解决方案
1. 修复本地代理的URL转发逻辑
调整xhr_proxy的处理规则,确保只对整个目标URL做一次URL编码,不要对路径中的特殊字符(比如冒号)进行二次编码。正确的目标URL应该是:
https://cognito-sync.us-east-1.amazonaws.com/identitypools/us-east-1:2bc13d33-35df-4da6-9c18-0e75a887eb38/identities/us-east-1:092beff5-9f9d-484f-a757-fc73531b0d2d/datasets
代理只需将整个URL作为rurl参数的一次编码值,而不是嵌套编码路径中的特殊字符。
2. 绕过本地代理直接请求CognitoSync
如果你的应用运行在浏览器环境,先确认CognitoSync服务的域名已经添加到AWS控制台的CORS允许列表中,然后修改代码直接调用CognitoSync端点,不再经过xhr_proxy:
// 确保CognitoSync客户端用正确区域初始化 this.cognitoSync = new window.aws.CognitoSync({ region: 'us-east-1' });
这样可以避免代理带来的URL编码问题,直接使用AWS SDK生成的正确签名请求。
3. 验证凭证和参数格式
- 确认
credentials.identityId的格式是原始的us-east-1:xxxx-xxxx字符串,没有被提前编码。 - 检查CognitoSync的
listDatasets参数是否正确,确保IdentityPoolId和IdentityId没有额外的编码或格式错误:
let params = { IdentityId: credentials.identityId, // 应为原始格式,如"us-east-1:092beff5-9f9d-484f-a757-fc73531b0d2d" IdentityPoolId: Config.awsIdentityPoolId // 同样为原始格式,如"us-east-1:2bc13d33-35df-4da6-9c18-0e75a887eb38" };
4. 升级AWS SDK版本
虽然你使用的是v2.471.0,但可以尝试升级到最新的v2.x版本,看看是否有针对CognitoSync签名逻辑的修复(AWS SDK会定期修复服务特定的签名问题)。
内容的提问来源于stack exchange,提问作者Allen
相关产品推荐
相关产品推荐

