在 React 中使用 aws-amplify 将文件上传到具有联合身份的 S3 时出错
Posted
技术标签:
【中文标题】在 React 中使用 aws-amplify 将文件上传到具有联合身份的 S3 时出错【英文标题】:Getting Error while uploading file to S3 with Federated Identity using aws-amplify in React 【发布时间】:2020-08-06 20:30:34 【问题描述】:当使用 Facebook 联合身份的用户尝试上传图片时,我收到一个错误:AWSS3Provider - 上传错误错误:“请求失败,状态码为 403” 状态码:403 禁止
注意到请求中的 URL,而用户通过联合身份 (Facebook) 进行身份验证时,看起来: 请求网址:https://my-gallery-api-dev-photorepos3bucket-XXXX.s3.us-east-2.amazonaws.com/private/undefined/1587639369473-image.jpg?x-id=PutObject
将放置上传图像的文件夹是'undefined',而不是像通过 AWS UserPool 进行身份验证的用户那样的有效用户身份,请参阅: 请求网址:https://my-gallery-api-dev-photorepos3bucket-XXXX.s3.us-east-2.amazonaws.com/private/us-east-2%3Aa2991437-264a-4652-a239-XXXXXXXXXXXX/1587636945392-image.jpg?x-id=PutObject
对于身份验证和上传,我正在使用 React aws 依赖项"aws-amplify": "^3.0.8"
Facebook 身份验证(Facebook 按钮):
async handleResponse(data)
console.log("FB Response data:", data);
const userID, accessToken: token, expiresIn = data;
const expires_at = expiresIn * 1000 + new Date().getTime();
const user = userID ;
this.setState( isLoading: true );
console.log("User:", user);
try
const response = await Auth.federatedSignIn(
"facebook",
token, expires_at ,
user
);
this.setState( isLoading: false );
console.log("federatedSignIn Response:", response);
this.props.onLogin(response);
catch (e)
this.setState( isLoading: false )
console.log("federatedSignIn Exception:", e);
alert(e.message);
this.handleError(e);
上传中:
import Storage from "aws-amplify";
export async function s3Upload(file)
const filename = `$Date.now()-$file.name`;
const stored = await Storage.vault.put(filename, file,
contentType: file.type
);
return stored.key;
const attachment = this.file
? await s3Upload(this.file)
: null;
我了解 S3 以 403 拒绝,由于 IAM 角色,我对经过身份验证的用户有:
# IAM role used for authenticated users
CognitoAuthRole:
Type: AWS::IAM::Role
Properties:
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Federated: 'cognito-identity.amazonaws.com'
Action:
- 'sts:AssumeRoleWithWebIdentity'
Condition:
StringEquals:
'cognito-identity.amazonaws.com:aud':
Ref: CognitoIdentityPool
'ForAnyValue:StringLike':
'cognito-identity.amazonaws.com:amr': authenticated
Policies:
- PolicyName: 'CognitoAuthorizedPolicy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'mobileanalytics:PutEvents'
- 'cognito-sync:*'
- 'cognito-identity:*'
Resource: '*'
# Allow users to invoke our API
- Effect: 'Allow'
Action:
- 'execute-api:Invoke'
Resource:
Fn::Join:
- ''
-
- 'arn:aws:execute-api:'
- Ref: AWS::Region
- ':'
- Ref: AWS::AccountId
- ':'
- Ref: ApiGatewayRestApi
- '/*'
# Allow users to upload attachments to their
# folder inside our S3 bucket
- Effect: 'Allow'
Action:
- 's3:*'
Resource:
- Fn::Join:
- ''
-
- Fn::GetAtt: [PhotoRepoS3Bucket, Arn]
- '/private/**$cognito-identity.amazonaws.com:sub/***'
- Fn::Join:
- ''
-
- Fn::GetAtt: [PhotoRepoS3Bucket, Arn]
- '/private/**$cognito-identity.amazonaws.com:sub**'
对于注册在 AWS 用户池(电子邮件、密码)中的用户可以正常工作,但是对于联合身份的用户,AWS 用户池中没有记录,只有联合身份,所以不会有 cognito-identity.amazonaws .com:sub 为那些用户和目录 'undefined' 不属于使用联合身份标识的用户的角色限额。
请指教: 1. 在哪里/如何在 URL 中修复这个 'undefined'? 2. 另外,我可能希望将上传 URL 中的 thouse Id 替换为我将在不久的将来添加的用户数据库中生成的用户 ID。如何修复 IAM 角色以使用自定义 ID?
【问题讨论】:
【参考方案1】:我在做Serverless Stack教程时遇到了同样的问题
当您执行 Extra Credit > React > Facebook Login with Cognito using AWS Amplify 时会出现此错误,因为您注意到如果您已通过 Facebook 身份验证,则上传文件会失败。
将 PUT 发送到:https://<bucket>.s3.amazonaws.com/private/<identity-id>/<file>
时出现错误
...<identity-id>
未定义,因此 PUT 失败。
如果您在运行登录命令时记录所获得的内容,则可以追踪此未定义的来源。例如,当您使用您的电子邮件和密码登录时,如果您这样做:
await Auth.signIn(fields.email, fields.password);
const currCreds = await Auth.currentCredentials();
console.log('currCreds', currCreds);
...可以看到identityId
设置正确。
另一方面,当您通过 Auth.federatedSignIn
登录 Facebook 时,如果您记录了回复,则不会收到 identityId
。注意:如果您之前使用电子邮件和密码登录,它将保持不变,因此此错误配置也会导致上传失败。
我使用的解决方法是添加一个简单的 lambda,它为已登录的用户返回 identityId
,因此一旦用户使用 facebook 登录,我们就会要求它,我们可以使用将 PUT 发送到正确的 url AWS.S3().putObject
如果您想尝试这个,请注意您应该在 https 中托管您的 React 应用程序,因为 Facebook 不允许使用 http 域。你可以设置这个添加 HTTPS=true
到你的 React .env 文件。
您可以查看我的回购作为示例:APIFrontend
【讨论】:
以上是关于在 React 中使用 aws-amplify 将文件上传到具有联合身份的 S3 时出错的主要内容,如果未能解决你的问题,请参考以下文章
aws-amplify-react 和 @aws-amplify/ui-react 有啥区别?
无法解析模块“@aws-amplify/ui-react/styles.css”的路径
如何使用 aws-amplify 验证 node/express 中的 accessToken?
AWS-amplify 在请求中包含 cognito Authorization 标头