amazon-web-services - 尝试在需要经过身份验证的访问的 S3 存储桶中获取对象时出现持续类型错误
问题描述
使用 AWS JavaScript 开发工具包,我正在尝试以经过身份验证的 Cognito 用户登录到我的网站的受保护区域来读取特定的 S3 存储桶。凭借在确认我的 Cognito 身份后获得的有效 authToken,我已验证我是以经过身份验证的用户身份进入的。事实上,我已经测试并证明了注册、多因素验证、登录和退出的整个 Cognito 流程。
出于某种原因,当我发出我的第一个 s3.getObject 请求时,我得到以下 TypeError 即使我是 CERTAIN 我传递一个字符串(密钥)作为第一个参数。这是错误:
TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
现在,首先,我通过 HTML 页面上的脚本标记包含 JavaScript SDK,如下所示:
script src="https://sdk.amazonaws.com/js/aws-sdk-2.154.0.min.js"></script>
我有 Cognito 创建的以下 IAM 角色:
Cognito_MyAppNameAuth_Role
我添加了以下 S3 策略:
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket-name"
},
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket-name/*"
}
注意:在我编辑之后,可视化编辑器会自动插入这些 Sid。
现在,我为读取 S3 存储桶而执行的代码位于一个 .js 文件中,我通过标签包含该文件。它在负载后运行...
<body onLoad="bodyOnLoad();">
代码所做的第一件事是验证用户凭据。我得到了用户池;然后我得到当前用户。然后我得到了会话。然后我使用 AWS.CognitoIdentityCredentials() 调用用户凭证,如下所示:
AWS.config.update({ //testing... 12/29
region: 'us-east-1',
accessKeyId: 'anything',
secretAccessKey: 'anything',
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:numbers-and-letters-and-bears-oh-my',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1-xxxyyyxxx': session.getIdToken().getJwtToken()
}
})
});
我从字面上为 accessKeyId 和 secretAccessKey 指定了“任何东西”,因为我认为这些不是必需的。当它运行时,没有错误。一切都按顺序显示,以验证我的经过身份验证的用户属于所需的 Cognito 身份池。
这是接下来发生的 s3.getObject 尝试,并导致上面给出的 TypeError:
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
params: {
Bucket: 'my-bucket-name'
}
});
var params = {
Bucket: 'my-bucket-name',
Key: 'index.json'
};
s3.getObject(params, (err, data) => {
if (err) {
// EXECUTION LANDS HERE!
callback(err);
return;
}
const content = data.Body.toString('utf-8');
callback(null, content);
});
}
我在将参数传递给 getObject 方法的方式上尝试了许多排列。包含..
s3.getObject({Key: 'index.json'}, (err, data) => { ... }
我每次都得到同样的错误。我到底做错了什么???先感谢您!!!
2019 年 1 月 1 日更新 - HNY!
回应下面的 John,我修改了我的代码以将所有内容移到同一范围内。(再次感谢。)很好的建议,但我仍然得到相同的 TypeError(如上所示)。现在,我认为 John 可能是对的,真正的问题在于我的身份验证或身份池策略。如果我从 AWS.config.update 中删除了伪造的 accessKeyId 和 secretAccessKey(正如 John 在他的示例中删除了这些),我确实会收到一个不同的错误:我收到一个 400 错误,然后这个..
Error: Invalid login token. Issuer doesn't match providerName
这是我在 config.js 中的代码:
window._config = {
cognito: {
userPoolId: 'user-pool-id',
userPoolClientId: 'user-pool-client-id',
region: 'us-east-1'
},
api: {
invokeUrl: 'https://<invoke-url>.execute-api.us-east-1.amazonaws.com/prod'
}
};
这是滚动到同一范围后的新代码流:
function loadFileFromS3(key, callback) {
console.log('loadFileFromS3: ' + key); //key is 'index.json'
var poolData = {
UserPoolId: _config.cognito.userPoolId,
ClientId: _config.cognito.userPoolClientId
};
var userPool;
userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
if (typeof AWSCognito !== 'undefined') {
AWSCognito.config.region = _config.cognito.region;
}
var cognitoUser = userPool.getCurrentUser();
if (cognitoUser) {
cognitoUser.getSession(function sessionCallback(err, session) {
if (err) {
reject(err);
} else if (!session.isValid()) {
resolve(null);
} else {
console.log('authToken is ' + session.getIdToken().getJwtToken());
// Configure the credentials provider to use your identity pool
AWS.config.update({ //testing... 12/29
region: 'us-east-1',
accessKeyId: 'anything', //remove gives me 400 error as shown above
secretAccessKey: 'anything', //
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:<identity-pool-id>',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1-<user-pool-id>': session.getIdToken().getJwtToken()
}
})
});
console.log('AWS.config update happened...');
// call refresh to authenticate user and get credentials
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
} else {
console.log('Success');
// NOTE: The credential are valid HERE
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
params: {
Bucket: 'my-bucket-name'
}
});
var params = {
Bucket: 'my-bucket-name',
Key: key
};
console.log('s3.getObject with key: ' + key);
s3.getObject(params, (err, data) => {
if (err) {
console.log('getObject ERROR: ' + err);
callback(err);
return;
}
const content = data.Body.toString('utf-8');
callback(null, content);
});
}
});
}
});
} else {
resolve(null);
}
}
更新
好的。这个问题与我传递给的论点无关,也与s3.getObject
我的 UserPoolId in 中的错字有关Logins
。我错过了一个下划线。呸!感谢 John 引导我进行修复。如果你不建议我仔细检查,我会永远挣扎。
更正上面的代码:
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1_<user-pool-id>': session.getIdToken().getJwtToken() //underscore after us-east-1_ !!!
解决方案
我认为您真正的问题是您没有用户的凭据。
AWS.config.update({ //testing... 12/29
region: 'us-east-1',
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:numbers-and-letters-and-bears-oh-my',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1-xxxyyyxxx': session.getIdToken().getJwtToken()
}
})
});
// call refresh to authenticate user and get credentials
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
} else {
console.log('Success');
// NOTE: The credential are valid HERE
// Put your S3 code HERE.
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
params: {
Bucket: 'my-bucket-name'
}
});
// Continue with the rest of your S3 code HERE
}
});
// The credentials are not valid HERE
推荐阅读
- java - 输入流不读取所有文件
- reactjs - redux 没有将动作连接到反应组件中的道具
- typescript - 打字稿从类型中排除类型
- python-3.x - 如何在 python3 中使用 Mercurial 的 Buildbot 钩子?
- javascript - 让我的不和谐机器人在特定时间发送消息
- c# - 无法将用户代理包含到我的标头中
- amazon-web-services - 通过 API Gateway 预热 Lambda
- c# - 从 Angular 发送并在 ASP.NET 服务器中接收时,日期值会发生变化
- ruby-on-rails - 使用 Inquisition gem 时的 Bundler::Source::Git::GitCommandError
- angular - ngx-uploader - 将 JSON 数据对象传递给 uploadInput 数据,返回 [object Object]