当前位置: 首页 > 知识库问答 >
问题:

403尝试使用PUT将PDF作为blob上载到S3存储桶时禁止

柯捷
2023-03-14

从浏览器客户端上载PDF文件,而不公开任何凭据或任何令人不快的内容。基于这一点,我认为这是可以做到的,但它似乎不适合我。

前提是:

>

  • 根据提供给JavaScript AWS SDK一部分的函数的一组参数,从S3 Bucket请求预签名URL

    您将此URL提供给前端,前端可以使用它将文件放入S3存储桶中,而无需在前端使用任何凭据或身份验证。

    这部分很简单,适合我。我只是请求一个URL从S3与这个小JS金块:

    const s3Params = {
        Bucket: uploadBucket,
        Key: `${fileId}.pdf`,
        ContentType: 'application/pdf',
        Expires: 60,
        ACL: 'public-read',
    }
    
    let uploadUrl = s3.getSignedUrl('putObject', s3Params);
    

    这是不起作用的部分,我不知道为什么。这一小块代码基本上是使用PUT请求向S3 bucket预签名URL发送一块数据。

    const result = await fetch(response.data.uploadURL, {
            method: 'put',
            body: blobData,
    });
    

    我发现使用任何POST请求都会导致400个错误请求,所以就这么说吧。

    内容类型(在我的例子中,应该是application/pdf,所以blobData.Type)——它们在后端和前端之间匹配。

    x-amz-acl头文件

    更多内容类型

    类似的用例。看看这一个,看起来PUT请求中不需要提供任何头,文件上传只需要签名的URL本身。

    一些我不明白的奇怪的事情。看起来我可能需要将文件的长度和类型传递给对S3的getSignedUrl调用。

    向公众公开我的桶(没有bueno)

    使用POST将文件上载到s3

    ...
    
    uploadFile: async function(e) {
          /* receives file from simple input element -> this.file */
          // get signed URL
          const response = await axios({
            method: 'get',
            url: API_GATEWAY_URL
          });
    
          console.log('upload file response:', response);
    
          let binary = atob(this.file.split(',')[1]);
          let array = [];
    
          for (let i = 0; i < binary.length; i++) {
            array.push(binary.charCodeAt(i));
          }
    
          let blobData = new Blob([new Uint8Array(array)], {type: 'application/pdf'});
          console.log('uploading to:', response.data.uploadURL);
          console.log('blob type sanity check:', blobData.type);
    
          const result = await fetch(response.data.uploadURL, {
            method: 'put',
            headers: {
              'Access-Control-Allow-Methods': '*',
              'Access-Control-Allow-Origin': '*',
              'x-amz-acl': 'public-read',
              'Content-Type': blobData.type
            },
            body: blobData,
          });
    
          console.log('PUT result:', result);
    
          this.uploadUrl = response.data.uploadURL.split('?')[0];
        }
    
    'use strict';
    
    const uuidv4 = require('uuid/v4');
    const aws = require('aws-sdk');
    const s3 = new aws.S3();
    
    const uploadBucket = 'the-chumiest-bucket';
    const fileKeyPrefix = 'path/to/where/the/file/should/live/';
    
    const getUploadUrl = async () => {
      const fileId = uuidv4();
      const s3Params = {
        Bucket: uploadBucket,
        Key: `${fileId}.pdf`,
        ContentType: 'application/pdf',
        Expires: 60,
        ACL: 'public-read',
      }
    
      return new Promise((resolve, reject) => {
        let uploadUrl = s3.getSignedUrl('putObject', s3Params);
        resolve({
          'statusCode': 200,
          'isBase64Encoded': false,
          'headers': { 
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Headers': '*',
            'Access-Control-Allow-Credentials': true,
          },
          'body': JSON.stringify({
            'uploadURL': uploadUrl,
            'filename': `${fileId}.pdf`
          })
        });
      });
    };
    
    exports.handler = async (event, context) => {
      console.log('event:', event);
      const result = await getUploadUrl();
      console.log('result:', result);
    
      return result;
    }
    
    service: ocr-space-service
    
    provider:
      name: aws
      region: ca-central-1
      stage: ${opt:stage, 'dev'}
      timeout: 20
    
    plugins:
      - serverless-plugin-existing-s3
      - serverless-step-functions
      - serverless-pseudo-parameters
      - serverless-plugin-include-dependencies
    
    layers:
      spaceOcrLayer:
        package:
          artifact: spaceOcrLayer.zip
        allowedAccounts:
          - "*"
    
    functions:
      fileReceiver:
        handler: src/node/fileReceiver.handler
        events:
          - http:
              path: /doc-parser/get-url
              method: get
              cors: true
      startStateMachine:
        handler: src/start_state_machine.lambda_handler
        role: 
        runtime: python3.7
        layers:
          - {Ref: SpaceOcrLayerLambdaLayer}
        events:
          - existingS3:
              bucket: ingenio-documents
              events:
                - s3:ObjectCreated:*
              rules:
                - prefix: 
                - suffix: .pdf
      startOcrSpaceProcess:
        handler: src/start_ocr_space.lambda_handler
        role: 
        runtime: python3.7
        layers:
          - {Ref: SpaceOcrLayerLambdaLayer}
      parseOcrSpaceOutput:
        handler: src/parse_ocr_space_output.lambda_handler
        role: 
        runtime: python3.7
        layers:
          - {Ref: SpaceOcrLayerLambdaLayer}
      renamePdf:
        handler: src/rename_pdf.lambda_handler
        role: 
        runtime: python3.7
        layers:
          - {Ref: SpaceOcrLayerLambdaLayer}
      parseCorpSearchOutput:
        handler: src/node/pdfParser.handler
        role: 
        runtime: nodejs10.x
      saveFileToProcessed:
        handler: src/node/saveFileToProcessed.handler
        role: 
        runtime: nodejs10.x
    
    stepFunctions:
      stateMachines:
        ocrSpaceStepFunc:
          name: ocrSpaceStepFunc
          definition:
            StartAt: StartOcrSpaceProcess
            States:
              StartOcrSpaceProcess:
                Type: Task
                Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:#{AWS::StackName}-startOcrSpaceProcess"
                Next: IsDocCorpSearchChoice
                Catch:
                - ErrorEquals: ["HandledError"]
                  Next: HandledErrorFallback
              IsDocCorpSearchChoice:
                Type: Choice
                Choices:
                  - Variable: $.docIsCorpSearch
                    NumericEquals: 1
                    Next: ParseCorpSearchOutput
                  - Variable: $.docIsCorpSearch
                    NumericEquals: 0
                    Next: ParseOcrSpaceOutput
              ParseCorpSearchOutput:
                Type: Task
                Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:#{AWS::StackName}-parseCorpSearchOutput"
                Next: SaveFileToProcessed
                Catch:
                  - ErrorEquals: ["SqsMessageError"]
                    Next: CorpSearchSqsErrorFallback
                  - ErrorEquals: ["DownloadFileError"]
                    Next: CorpSearchDownloadFileErrorFallback
                  - ErrorEquals: ["HandledError"]
                    Next: HandledNodeErrorFallback
              SaveFileToProcessed:
                Type: Task
                Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:#{AWS::StackName}-saveFileToProcessed"
                End: true
              ParseOcrSpaceOutput:
                Type: Task
                Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:#{AWS::StackName}-parseOcrSpaceOutput"
                Next: RenamePdf
                Catch:
                - ErrorEquals: ["HandledError"]
                  Next: HandledErrorFallback
              RenamePdf:
                Type: Task
                Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:#{AWS::StackName}-renamePdf"
                End: true
                Catch:
                  - ErrorEquals: ["HandledError"]
                    Next: HandledErrorFallback
                  - ErrorEquals: ["AccessDeniedException"]
                    Next: AccessDeniedFallback
              AccessDeniedFallback:
                Type: Fail
                Cause: "Access was denied for copying an S3 object"
              HandledErrorFallback:
                Type: Fail
                Cause: "HandledError occurred"
              CorpSearchSqsErrorFallback:
                Type: Fail
                Cause: "SQS Message send action resulted in error"
              CorpSearchDownloadFileErrorFallback:
                Type: Fail
                Cause: "Downloading file from S3 resulted in error"
              HandledNodeErrorFallback:
                Type: Fail
                Cause: "HandledError occurred"
    
    

    403禁止

    响应{type:“cors”,url:“https://{bucket name}.s3.{region id}.amazonaw…nedHeaders=host;x-amz-acl

    我认为使用AWS S3 SDK提供给getSignedUrl调用的参数是不正确的,尽管它们遵循AWS文档(此处解释)建议的结构。除此之外,我真的不明白为什么我的请求被拒绝了。我甚至试着把我的水桶完全公开,但还是不起作用。

    在阅读本文之后,我尝试将我的PUT请求构造为:

          let authFromGet = response.config.headers.Authorization;      
    
          const putHeaders = {
            'Authorization': authFromGet,
            'Content-Type': blobData,
            'Expect': '100-continue',
          };
    
          ...
    
          const result = await fetch(response.data.uploadURL, {
            method: 'put',
            headers: putHeaders,
            body: blobData,
          });
    

    这导致一个400错误请求,而不是403;不同,但仍然是错误的。显然,在请求上放置任何标题都是错误的。

  • 共有1个答案

    莫选
    2023-03-14

    深入研究这一点,是因为您试图将具有公共ACL的对象上载到不允许公共对象的bucket中。

    >

  • (可选)删除公共ACL语句或。。。

    确保铲斗设置为

    • 公开可见或
    • 确保没有其他策略阻止公共访问(例如:您是否有帐户策略防止公开可见的对象,但试图用公共ACL上传对象?(

    基本上,您无法将具有公共ACL的对象上载到存在某些限制的bucket中,您将得到您描述的403错误。嗯。

  •  类似资料:
    • 有没有一种方法可以将文件列表从一个S3存储桶复制到另一个存储桶?两个S3存储桶都在同一个AWS帐户中。我可以使用aws cli命令一次复制一个文件: 然而,我有1000份文件要复制。我不想复制源存储桶中的所有文件,因此无法使用sync命令。有没有一种方法可以用需要复制的文件名列表来调用一个文件,从而自动化这个过程?

    • 如果有人帮我解决这个问题,我会非常感激。 我正在为我的项目使用codeigniter框架。并想将我的图像上传到amazon s3桶中。当我尝试使用S3.php文件时 string(92)“不支持您提供的授权机制。请使用AWS4-HMAC-SHA256。” 有人能帮我解决这个问题吗。

    • 我用的是fs。readFile读取大约700KB的本地mp4文件,AWS SDK将文件加载到我的S3存储桶中。这个过程是可行的,但文件已损坏,可能是因为S3上生成的文件大小仅为500KB左右而被截断。 我使用的代码可以很好地处理图像。只是不适用于mp4文件。这是我的代码: 我已尝试从params对象中省略ContentEncoding和/或ContentType属性。 编辑: 因此,当我conso

    • 我在尝试将文件上载到blob存储时遇到此错误。在本地主机上运行和在Azure函数中运行时都会出现错误。 我的连接字符串如下所示:DefaultEndpoint sProtocol=https; AcCountName=xxx; AcCountKey=xxx; Endpoint Suffix=core.windows.net 身份验证信息的格式不正确。检查授权标头的值。时间:2021 10月14日1

    • 如果我能知道根本原因是什么就好了。