2017-08-29 10 views
0

更新:このメッセージの下部に表示されています。これはpython3/hmacバージョンの問題です。fineuploaderとdjangoを含むファイルをS3にアップロードする際の署名エラーメッセージ

私はファインアップローダー、S3とdjango 1.11でファイルアップロードシステムを設定しています。応答コード400 -

  • [ファインアップローダー5.15.0] 0のためのPOST要求は失敗しました:ここ IセットアップのURL、テンプレートおよびビューだが、ファイルをアップロードしようとしたときに私が取得(クライアント)のエラーメッセージです
  • [Fine Uploader 5.15.0]署名レスポンスの解析中にエラーが発生しました:SyntaxError:JSON解析エラー:予期しない識別子「無効」
  • [Fine Uploader 5.15.0]サーバーからの応答が無効です。
  • [Fine Uploader 5.15.0]ポリシーに署名できませんでした。サーバーから空または無効な応答を受信しました。

ファインアップローダーは、Djangoの設定で必要になります。キー

  • AWS_SERVER_PUBLIC_KEY = IAMユーザーアクセスキーID
  • AWS_SERVER_SECRET_KEY = IAMユーザーシークレットアクセスキー

    • AWS_CLIENT_SECRET_KEY = IAMユーザーの秘密のアクセスを

    私は私ですアクセスキーID秘密のアクセスキーをiamユーザーから作成し、上記のように設定しました。 AWS_CLIENT_SECRET_KEY = AWS_SERVER_SECRET_KEY = IAMユーザ秘密鍵。私はこれが正しいとは確信していないし、よく問題があるかもしれませんが、私はAWS_CLIENT_SECRET_KEYとAWS_SERVER_SECRET_KEYの違いは何かを知りません。

    そして、ここのコードです:

    ビュー:

    from django.shortcuts import render 
    from django.conf import settings 
    from django.http import HttpResponse, HttpRequest 
    from django.shortcuts import render 
    from django.views.decorators.http import require_http_methods 
    from django.views.decorators.csrf import csrf_exempt 
    
    import base64, hmac, hashlib, json, sys 
    
    
    import boto 
    from boto.s3.connection import Key, S3Connection 
    
    boto.set_stream_logger('boto') 
    S3 = S3Connection(settings.AWS_SERVER_PUBLIC_KEY, settings.AWS_SERVER_SECRET_KEY) 
    
    
    def video_create_form(request): 
        return render(request, 'video_create_form_view.html') 
    
    
    @csrf_exempt 
    def success_redirect_endpoint(request): 
        """ This is where the upload will snd a POST request after the 
        file has been stored in S3. 
        """ 
        return make_response(200) 
    
    
    @csrf_exempt 
    def handle_s3(request): 
        """ View which handles all POST and DELETE requests sent by Fine Uploader 
        S3. You will need to adjust these paths/conditions based on your setup. 
        """ 
        if request.method == "POST": 
         return handle_POST(request) 
        elif request.method == "DELETE": 
         return handle_DELETE(request) 
        else: 
         return HttpResponse(status = 405) 
    
    
    def handle_POST(request): 
        """ Handle S3 uploader POST requests here. For files <=5MiB this is a simple 
        request to sign the policy document. For files >5MiB this is a request 
        to sign the headers to start a multipart encoded request. 
        """ 
        if request.POST.get('success', None): 
         return make_response(200) 
        else: 
         request_payload = json.loads(request.body) 
         headers = request_payload.get('headers', None) 
         if headers: 
          # The presence of the 'headers' property in the request payload 
          # means this is a request to sign a REST/multipart request 
          # and NOT a policy document 
          response_data = sign_headers(headers) 
         else: 
          if not is_valid_policy(request_payload): 
           return make_response(400, { 'invalid': True }) 
          response_data = sign_policy_document(request_payload) 
         response_payload = json.dumps(response_data) 
         return make_response(200, response_payload) 
    
    
    def handle_DELETE(request): 
        """ Handle file deletion requests. For this, we use the Amazon Python SDK, 
        boto. 
        """ 
        if boto: 
         bucket_name = request.REQUEST.get('bucket') 
         key_name = request.REQUEST.get('key') 
         aws_bucket = S3.get_bucket(bucket_name, validate = False) 
         aws_key = Key(aws_bucket, key_name) 
         aws_key.delete() 
         return make_response(200) 
        else: 
         return make_response(500) 
    
    
    def make_response(status = 200, content = None): 
        """ Construct an HTTP response. Fine Uploader expects 'application/json'. 
        """ 
        response = HttpResponse() 
        response.status_code = status 
        response[ 'Content-Type' ] = "application/json" 
        response.content = content 
        return response 
    
    
    def is_valid_policy(policy_document): 
        """ Verify the policy document has not been tampered with client-side 
        before sending it off. 
        """ 
        # bucket = settings.AWS_EXPECTED_BUCKET 
        # parsed_max_size = settings.AWS_MAX_SIZE 
        bucket = '' 
        parsed_max_size = 0 
    
        for condition in policy_document[ 'conditions' ]: 
         if isinstance(condition, list) and condition[ 0 ] == 'content-length-range': 
          parsed_max_size = condition[ 2 ] 
         else: 
          if condition.get('bucket', None): 
           bucket = condition[ 'bucket' ] 
    
        return bucket == settings.AWS_EXPECTED_BUCKET and parsed_max_size == settings.AWS_MAX_SIZE 
    
    
    def sign_policy_document(policy_document): 
        """ Sign and return the policy doucument for a simple upload. 
        http://aws.amazon.com/articles/1434/#signyours3postform 
        """ 
        policy = base64.b64encode(json.dumps(policy_document)) 
        signature = base64.b64encode(
          hmac.new(settings.AWS_CLIENT_SECRET_KEY, policy, hashlib.sha1).digest()) 
        return { 
         'policy' : policy, 
         'signature': signature 
        } 
    
    
    def sign_headers(headers): 
        """ Sign and return the headers for a chunked upload. """ 
        return { 
         'signature': base64.b64encode(
           hmac.new(settings.AWS_CLIENT_SECRET_KEY, headers, hashlib.sha1).digest()) 
        } 
    

    は、テンプレート:(ファイルのURLもにインポート)

    {% load static %} 
    
    <!DOCTYPE html> 
    <html> 
    <head> 
        <meta charset="utf-8"> 
        <meta name="viewport" content="width=device-width, initial-scale=1"> 
        <link href="{% static "fine-uploader-gallery.css" %}" rel="stylesheet"> 
        <script src="{% static "s3.fine-uploader.js" %}"></script> 
    
    
        <title>Fine Uploader Gallery UI</title> 
    </head> 
    <body> 
    <div id="uploader"></div> 
    
    <script type="text/template" id="qq-template"> 
        <div class="qq-uploader-selector qq-uploader qq-gallery" 
         qq-drop-area-text="Drop files here"> 
         <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container"> 
          <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" 
           class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div> 
         </div> 
         <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone> 
          <span class="qq-upload-drop-area-text-selector"></span> 
         </div> 
         <div class="qq-upload-button-selector qq-upload-button"> 
          <div>Upload a file</div> 
         </div> 
         <span class="qq-drop-processing-selector qq-drop-processing"> 
           <span>Processing dropped files...</span> 
           <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span> 
          </span> 
         <ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" 
          aria-relevant="additions removals"> 
          <li> 
            <span role="status" 
              class="qq-upload-status-text-selector qq-upload-status-text"></span> 
           <div class="qq-progress-bar-container-selector qq-progress-bar-container"> 
            <div role="progressbar" aria-valuenow="0" aria-valuemin="0" 
             aria-valuemax="100" 
             class="qq-progress-bar-selector qq-progress-bar"></div> 
           </div> 
           <span class="qq-upload-spinner-selector qq-upload-spinner"></span> 
           <div class="qq-thumbnail-wrapper"> 
            <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale> 
           </div> 
           <button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X 
           </button> 
           <button type="button" class="qq-upload-retry-selector qq-upload-retry"> 
            <span class="qq-btn qq-retry-icon" aria-label="Retry"></span> 
            Retry 
           </button> 
    
           <div class="qq-file-info"> 
            <div class="qq-file-name"> 
             <span class="qq-upload-file-selector qq-upload-file"></span> 
             <span class="qq-edit-filename-icon-selector qq-btn qq-edit-filename-icon" 
               aria-label="Edit filename"></span> 
            </div> 
            <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" 
              type="text"> 
            <span class="qq-upload-size-selector qq-upload-size"></span> 
            <button type="button" 
              class="qq-btn qq-upload-delete-selector qq-upload-delete"> 
             <span class="qq-btn qq-delete-icon" aria-label="Delete"></span> 
            </button> 
            <button type="button" 
              class="qq-btn qq-upload-pause-selector qq-upload-pause"> 
             <span class="qq-btn qq-pause-icon" aria-label="Pause"></span> 
            </button> 
            <button type="button" 
              class="qq-btn qq-upload-continue-selector qq-upload-continue"> 
             <span class="qq-btn qq-continue-icon" aria-label="Continue"></span> 
            </button> 
           </div> 
          </li> 
         </ul> 
    
         <dialog class="qq-alert-dialog-selector"> 
          <div class="qq-dialog-message-selector"></div> 
          <div class="qq-dialog-buttons"> 
           <button type="button" class="qq-cancel-button-selector">Close</button> 
          </div> 
         </dialog> 
    
         <dialog class="qq-confirm-dialog-selector"> 
          <div class="qq-dialog-message-selector"></div> 
          <div class="qq-dialog-buttons"> 
           <button type="button" class="qq-cancel-button-selector">No</button> 
           <button type="button" class="qq-ok-button-selector">Yes</button> 
          </div> 
         </dialog> 
    
         <dialog class="qq-prompt-dialog-selector"> 
          <div class="qq-dialog-message-selector"></div> 
          <input type="text"> 
          <div class="qq-dialog-buttons"> 
           <button type="button" class="qq-cancel-button-selector">Cancel</button> 
           <button type="button" class="qq-ok-button-selector">Ok</button> 
          </div> 
         </dialog> 
        </div> 
    </script> 
    
    <script> 
        var uploader = new qq.s3.FineUploader({ 
         debug  : true, 
         element  : document.getElementById('uploader'), 
         request  : { 
          endpoint : 'https://mybucketname.s3.amazonaws.com', 
          accessKey: 'AK*******' 
         }, 
         signature : { 
          endpoint: '/videos/s3/signature' 
         }, 
         uploadSuccess: { 
          endpoint: '/videos/s3/success' 
         }, 
         iframeSupport: { 
          localBlankPagePath: '/success.html' 
         }, 
         retry  : { 
          enableAuto: true // defaults to false 
         }, 
         deleteFile : { 
          enabled : true, 
          endpoint: '/videos/s3/delete' 
         } 
        }); 
    </script> 
    </body> 
    </html> 
    

    のURL

    from django.conf.urls import url 
    from videos.controllers.video_create_controller import video_create_form, handle_s3, success_redirect_endpoint 
    
    
    urlpatterns = [ 
        url(r'^video-create-form/$', video_create_form, name = 'video_create_form'), 
        url(r'^s3/signature', handle_s3, name = "s3_signee"), 
        url(r'^s3/delete', handle_s3, name = 's3_delete'), 
        url(r'^s3/success', success_redirect_endpoint, name = "s3_succes_endpoint") 
    ] 
    

    設定

    # Amazon variables. Be wary and don't hard-code your secret keys here. Rather, 
    # set them as environment variables, or read them from a file somehow. 
    AWS_CLIENT_SECRET_KEY = 'WDq/cy*****' 
    AWS_SERVER_PUBLIC_KEY = 'AK*****' 
    AWS_SERVER_SECRET_KEY = 'WDq/cy*****' 
    
    AWS_EXPECTED_BUCKET = 'mybucketname' 
    AWS_MAX_SIZE = 15000000 
    

    CORSポリシー

    それは私が他の手段で私のバケットにファイルを取得することができるよと、AWS側の設定の問題ではありません。

    <?xml version="1.0" encoding="UTF-8"?> 
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 
    <CORSRule> 
        <AllowedOrigin>*</AllowedOrigin> 
        <AllowedMethod>GET</AllowedMethod> 
        <AllowedMethod>HEAD</AllowedMethod> 
        <AllowedMethod>PUT</AllowedMethod> 
        <AllowedMethod>POST</AllowedMethod> 
        <MaxAgeSeconds>3000</MaxAgeSeconds> 
        <ExposeHeader>ETag</ExposeHeader> 
        <AllowedHeader>*</AllowedHeader> 
    </CORSRule> 
    </CORSConfiguration> 
    

    UPDATE: Pythonのバージョンに問題があるようです:FLASKでインストールを再生した後、私は、HMACに関するこのエラーメッセージを取得することができた:

    のpythonとvenvの設定
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) 
    TypeError: key: expected bytes or bytearray, but got 'str 
    

    2.7で問題が修正され、すべてのプロセスが機能していた。私は問題を調査しています、誰かが修正を持っているなら教えてください。

    '

  • +0

    ステータスコードは通常、送信されたデータが無効であることを示します。ブラウザーのdevパネルで検索すると、要求に応じてどのデータが送信されますか。 – Chikiro

    +0

    これはpythonバージョンの問題です。更新された投稿を参照してください。 –

    +0

    解決策が見つかったらうれしいです。^ _^ – Chikiro

    答えて

    0

    python 3とBoto3で動作するように完全に更新されたビューコードを示します。 あなたのpython 3.6を使用していて、ファイルを削除するときにSSLエラーの問題を取得している場合は、お使いのMacのコマンドラインから

    /Applications/Python\ 3.6/Install\ Certificates.command 
    

    を実行する必要があります。

    これはawsや許可の問題ではありませんでしたが、python3バイト/文字列の問題です。

    return bucket == settings.AWS_EXPECTED_BUCKET and parsed_max_size == settings.AWS_MAX_SIZE 
    

    いかなる意味のあるエラーメッセージの表示を防止: はまた、常にfalseが返され、このラインで型強制の問題がありました。

    from django.conf import settings 
    from django.http import HttpResponse 
    from django.shortcuts import render 
    from django.views.decorators.csrf import csrf_exempt 
    
    import base64, hmac, hashlib, json 
    
    import boto3 
    
    # Enforce session to inject credentials 
    session = boto3.Session(
         aws_access_key_id = settings.AWS_SERVER_PUBLIC_KEY, 
         aws_secret_access_key = settings.AWS_SERVER_SECRET_KEY, 
    ) 
    S3 = session.resource('s3') 
    
    
    def video_create_form(request): 
        return render(request, 'video_create_form_view.html') 
    
    
    @csrf_exempt 
    def success_redirect_endpoint(request): 
        """ This is where the upload will send a POST request after the 
        file has been stored in S3. 
        """ 
        return make_response(200) 
    
    
    @csrf_exempt 
    def handle_s3(request): 
        """ View which handles all POST and DELETE requests sent by Fine Uploader 
        S3. You will need to adjust these paths/conditions based on your setup. 
        """ 
        if request.method == "POST": 
         return handle_POST(request) 
        elif request.method == "DELETE": 
         return handle_DELETE(request) 
        else: 
         return HttpResponse(status = 405) 
    
    
    def handle_POST(request): 
        """ Handle S3 uploader POST requests here. For files <=5MiB this is a simple 
        request to sign the policy document. For files >5MiB this is a request 
        to sign the headers to start a multipart encoded request. 
        """ 
        class MyEncoder(json.JSONEncoder): 
         """Converts a dict of bytes to Json""" 
         def default(self, obj): 
          if isinstance(obj, (bytes, bytearray)): 
           return obj.decode("ASCII") # <- or any other encoding of your choice 
          # Let the base class default method raise the TypeError 
          return json.JSONEncoder.default(self, obj) 
    
        if request.POST.get('success', None): 
         return make_response(200) 
        else: 
         request_payload = json.loads(request.body) 
         headers = request_payload.get('headers', None) 
         if headers: 
          # The presence of the 'headers' property in the request payload 
          # means this is a request to sign a REST/multipart request 
          # and NOT a policy document 
          response_data = sign_headers(headers) 
         else: 
          if not is_valid_policy(request_payload): 
           return make_response(400, { 'invalid': True }) 
          response_data = sign_policy_document(request_payload) 
         response_payload = json.dumps(response_data, cls = MyEncoder) 
         return make_response(200, response_payload) 
    
    
    def handle_DELETE(request): 
        """ Handle file deletion requests. For this, we use the Amazon Python SDK, boto. 
        """ 
        if boto3: 
         bucket_name = request.GET.get('bucket') 
         key_name = request.GET.get('key') 
         S3.Object(bucket_name, key_name).delete() 
    
         return make_response(200) 
        else: 
         return make_response(500) 
    
    
    def make_response(status = 200, content = None): 
        """ Construct an HTTP response. Fine Uploader expects 'application/json'. 
        """ 
        response = HttpResponse() 
        response.status_code = status 
        response[ 'Content-Type' ] = "application/json" 
        response.content = content 
        return response 
    
    
    def is_valid_policy(policy_document): 
        """ Verify the policy document has not been tampered with client-side 
        before sending it off. 
        """ 
        # bucket = settings.AWS_EXPECTED_BUCKET 
        # parsed_max_size = settings.AWS_MAX_SIZE 
        bucket = '' 
        parsed_max_size = 0 
    
        for condition in policy_document[ 'conditions' ]: 
         if isinstance(condition, list) and condition[ 0 ] == 'content-length-range': 
          parsed_max_size = condition[ 2 ] 
         else: 
          if condition.get('bucket', None): 
           bucket = condition[ 'bucket' ] 
    
        return bucket == settings.AWS_EXPECTED_BUCKET and int(
          parsed_max_size) == settings.AWS_MAX_SIZE 
    
    
    def sign_policy_document(policy_document): 
        """ Sign and return the policy doucument for a simple upload. 
        http://aws.amazon.com/articles/1434/#signyours3postform 
        """ 
        policy_document_string = str.encode(str(policy_document)) 
        policy = base64.b64encode(policy_document_string) 
        aws_secret_key = settings.AWS_CLIENT_SECRET_KEY 
        secret_key = str.encode(aws_secret_key) 
    
        signature = base64.b64encode(
          hmac.new(secret_key, policy, hashlib.sha1).digest()) 
        return { 
         'policy' : policy, 
         'signature': signature 
        } 
    
    
    def sign_headers(headers): 
        """ Sign and return the headers for a chunked upload. """ 
        headers_bytes = bytearray(headers, 'utf-8') # hmac doesn't want unicode 
        aws_client_secret = str.encode(settings.AWS_CLIENT_SECRET_KEY) 
        return { 
         'signature': base64.b64encode(
           hmac.new(aws_client_secret, headers_bytes, hashlib.sha1).digest()) 
        } 
    
    関連する問題