繁体   English   中英

在 React 中使用 aws-amplify 将文件上传到具有联合身份的 S3 时出错

[英]Getting Error while uploading file to S3 with Federated Identity using aws-amplify in React

当具有 Facebook 联合身份的用户尝试上传图像时,我收到一个错误:AWSS3Provider - 上传错误错误:“请求失败,状态代码为 403”状态代码:403 Forbidden

注意到请求中的 URL 在用户使用联合身份 (Facebook) 进行身份验证时看起来:
请求 URL: https://my-gallery-api-dev-photorepos3bucket-XXXX.s3.us-east-2.amazonaws.com/private/undefined/1587639-369473-image.jpg?

将放置上传图像的文件夹是“未定义” ,而不是像通过 AWS UserPool 进行身份验证的用户那样的有效用户身份,请参阅:
Request URL: 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;

我知道由于 IAM 角色,S3 以 403 拒绝了经过身份验证的用户:

  # 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 found for那些用户和目录“未定义”不属于使用联合身份标识的用户的角色允许范围。

请指教:
1. 在哪里/如何在 URL 中修复这个“未定义”
2. 另外,我可能希望将上传 URL 中的 thouse Id 替换为我将在不久的将来添加的用户数据库中生成的用户 Id。 如何修复 IAM 角色以使用自定义 ID?

在做无服务器堆栈教程时,我偶然发现了同样的问题

当您执行 Extra Credit > React > Facebook Login with Cognito using AWS Amplify时会出现此错误,因为您注意到如果您通过 Facebook 进行身份验证,上传文件将失败。

将 PUT 发送到:
https://<bucket>.s3.amazonaws.com/private/<identity-id>/<file>
... <identity-id>未定义,因此 PUT 失败。

如果您记录运行登录命令时获得的内容,则可以追踪此未定义的来源。 例如,当您使用 email 和密码登录时,如果您这样做:

await Auth.signIn(fields.email, fields.password);
const currCreds = await Auth.currentCredentials();
console.log('currCreds', currCreds);

...您可以看到identityId设置正确。

另一方面,当您通过Auth.federatedSignIn使用 Facebook 登录时,如果您记录响应,您不会得到identityId 注意:如果您之前使用 email 和密码登录,它将保持不变,因此此错误配置也会导致上传失败。

The workaround I've used is adding a simple lambda which returns the identityId for the logged in user, so once the user logs in with facebook, we ask for it and we can send the PUT to the correct url using AWS.S3().putObject

如果您想尝试这个,请考虑到您应该在 https 中托管您的 React 应用程序,因为 Facebook 不允许 http 域。 你可以设置这个添加HTTPS=true到你的 React.env 文件。

您可以查看我的回购作为示例:
API
前端

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM