2017-02-18 47 views
2

一些背景信息,如何使用AWS Web API和Lambda驗證無服務器Web請求?

我已經建立了一個互動網站,用戶可以上傳圖片到S3。我構建它,以便使用簽名請求(python django後端)將圖像上傳從瀏覽器轉移到AWS S3。

現在的問題是,用戶希望能夠旋轉圖像。我同樣我想這樣設置,以便用戶的請求直接從瀏覽器中獲得。我構建了一個AWS Lambda函數,並將其附加到一個Web API,它將接受POST請求。我一直在測試,我終於找到了工作。該函數需要2個輸入,keyrotate_direction,它們作爲POST變量傳遞給Web API。他們進入event變量的python函數。這裏是簡單的Lambda功能:

from __future__ import print_function 
import boto3 
import os 
import sys 
import uuid 
from PIL import Image 

s3_client = boto3.client('s3') 

def rotate_image(image_path, upload_path, rotate_direction): 
    with Image.open(image_path) as image: 
     if rotate_direction == "right": 
      image.rotate(-90).save(upload_path) 
     else: 
      image.rotate(90).save(upload_path) 

def handler(event, context): 
    bucket = 'the-s3-bucket-name' 
    key = event['key'] 
    rotate_direction = event['rotate_direction'] 
    download_path = '/tmp/{}{}'.format(uuid.uuid4(), key) 
    upload_path = '/tmp/rotated_small-{}'.format(key) 


    s3_client.download_file(bucket, key, download_path) 
    rotate_image(download_path, upload_path, rotate_direction) 
    s3_client.delete_object(Bucket=bucket, Key=key) 
    s3_client.upload_file(upload_path, bucket, key) 

    return { 'message':'rotated' } 

一切正常。所以現在我的問題是如何執行這種系統的某種認證?有關每個圖像的所有權詳細信息駐留在django Web服務器上。雖然所有圖像都被視爲「公開」,但我希望強制規定只允許每個圖像的所有者旋轉自己的圖像。

通過這個項目我已經被直接從瀏覽器進行內容的請求冒險進入新的領域。我可以理解我如何通過僅從Web服務器發出POST請求來控制訪問,我可以驗證圖像的所有權。請求來自瀏覽器還有可能嗎?

回答

3

TL; DR解決方案:創建一個Cognito身份池,分配政策,用戶只能上傳他們的身份ID前綴的文件。

如果我正確理解你的問題,你要設置的方式爲公共存儲在S3是可視的圖像,但只有通過誰上傳它用戶編輯。實際上,您可以驗證文件所有權,旋轉圖像並將瀏覽過的圖像上傳到瀏覽器中的所有S3,而無需通過Lambda函數。

步驟1:創建Cognito用戶池以創建用戶目錄。如果您已經有用戶登錄/註冊認證系統,則可以跳過此步驟。

第2步:創建一個Cognito確定池啓用聯合身份,以便用戶可以從身份池臨時AWS憑證,並用它來上傳文件到S3不通過你的服務器/λ去。

第3步:在創建Cognito身份游泳池,您可以定義什麼S3資源的用戶被允許訪問的策略。下面是一個簡單的政策

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
    { 
     "Effect": "Allow", 
     "Action": [ 
     "mobileanalytics:PutEvents", 
     "cognito-sync:*", 
     "cognito-identity:*" 
     ], 
     "Resource": [ 
     "*" 
     ] 
    }, 
    { 
     "Effect": "Allow", 
     "Action": [ 
     "s3:GetObject" 
     ], 
     "Resource": [ 
     "arn:aws:s3:::YOUR_S3_UPLOADS_BUCKET_NAME/*" 
     ] 
    }, 
    { 
     "Effect": "Allow", 
     "Action": [ 
     "s3:PutObject" 
     ], 
     "Resource": [ 
     "arn:aws:s3:::YOUR_S3_UPLOADS_BUCKET_NAME/${cognito-identity.amazonaws.com:sub}*" 
     ] 
    } 
    ] 
} 

注二等塊分配「S3:GetObject的」在你的S3存儲桶中的所有文件;第三個塊將「S3:PutObject」分配給以用戶的Cognito身份標識爲前綴的ONLY FILES。

步驟4:在前臺JS,從Cognito身份池獲得一個臨時證書

export function getAwsCredentials(userToken) { 
    const authenticator = `cognito-idp.${config.cognito.REGION}.amazonaws.com/${config.cognito.USER_POOL_ID}`; 

    AWS.config.update({ region: config.cognito.REGION }); 

    AWS.config.credentials = new AWS.CognitoIdentityCredentials({ 
    IdentityPoolId: config.cognito.IDENTITY_POOL_ID, 
    Logins: { 
     [authenticator]: userToken 
    } 
    }); 

    return new Promise((resolve, reject) => (
    AWS.config.credentials.get((err) => { 
     if (err) { 
     reject(err); 
     return; 
     } 

     resolve(); 
    }) 
)); 
} 

第5步:上傳文件到S3與證書,與用戶的Cognito身份ID前綴的文件名。

export async function s3Upload(file, userToken) { 
    await getAwsCredentials(userToken); 

    const s3 = new AWS.S3({ 
    params: { 
     Bucket: config.s3.BUCKET, 
    } 
    }); 
    const filename = `${AWS.config.credentials.identityId}-${Date.now()}-${file.name}`; 

    return new Promise((resolve, reject) => (
    s3.putObject({ 
     Key: filename, 
     Body: file, 
     ContentType: file.type, 
     ACL: 'public-read', 
    }, 
    (error, result) => { 
     if (error) { 
     reject(error); 
     return; 
     } 

     resolve(`${config.s3.DOMAIN}/${config.s3.BUCKET}/${filename}`); 
    }) 
)); 
} 
+0

這是一個相當強的答案。非常感謝。將通過教程閱讀,看看如何整合這一點。我的應用程序實際上使用Firebase進行用戶身份驗證,但文件上傳使用來自服務器的「已批​​準的請求」(http://boto3.readthedocs.io/en/latest/guide/s3.html#generating-presigned-urls),以及在客戶端可以上傳圖像之前將其傳回客戶端。這似乎與你的技術,我可以跳過這一步(少服務器)。此外,現在所有的圖像都沒有任何特殊的前綴,所以我將不得不重新工作。 –

+1

很高興你找到了解決辦法。是的,根據亞馬遜的文檔,您要麼以文件名爲前綴,要麼將圖像存儲在用戶標識前綴的文件夾名稱中。 – Frank

+0

是的,現在你說這個,我意識到他們是如何處理我已經在其他項目上的文件命名。我想我並不需要它,因爲數據庫中的數據庫包含所有權信息,但現在我可以看到如何爲每個用戶提供特殊代碼的命名可以提供幫助。 –