尝试在需要经过身份验证的访问的 S3 存储桶中获取对象时出现持续类型错误
Persistent typeerror on trying to getObject in S3 bucket requiring authenticated access
使用 AWS JavaScript SDK,我正在尝试读取特定的 S3 存储桶,作为已验证的 Cognito 用户登录到我网站的受保护区域。凭借确认我的 Cognito 身份后获得的有效 authToken,我已经验证我是以经过身份验证的用户身份进入的。事实上,我已经测试并证明了注册、多因素验证、登录和退出的整个 Cognito 流程。
出于某种原因,当我发出我的第一个 s3.getObject 请求时,我得到了以下 TypeError,即使我确定我正在传递一个字符串(密钥)作为第一个参数。这是错误:
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/*"
}
注意:Visual Editor 会在我编辑后自动插入这些 Sids。
现在,我为读取 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 指定了 "anything",因为我认为这些不是必需的。运行时,没有错误。一切都按顺序显示,以验证我的经过身份验证的用户属于所需的 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
的参数无关,而与我在 Logins
中的 UserPoolId 中的拼写错误有关。我错过了一个下划线。啊!感谢 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
使用 AWS JavaScript SDK,我正在尝试读取特定的 S3 存储桶,作为已验证的 Cognito 用户登录到我网站的受保护区域。凭借确认我的 Cognito 身份后获得的有效 authToken,我已经验证我是以经过身份验证的用户身份进入的。事实上,我已经测试并证明了注册、多因素验证、登录和退出的整个 Cognito 流程。
出于某种原因,当我发出我的第一个 s3.getObject 请求时,我得到了以下 TypeError,即使我确定我正在传递一个字符串(密钥)作为第一个参数。这是错误:
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/*"
}
注意:Visual Editor 会在我编辑后自动插入这些 Sids。
现在,我为读取 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 指定了 "anything",因为我认为这些不是必需的。运行时,没有错误。一切都按顺序显示,以验证我的经过身份验证的用户属于所需的 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
的参数无关,而与我在 Logins
中的 UserPoolId 中的拼写错误有关。我错过了一个下划线。啊!感谢 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