简体   繁体   English

如何使用AWS Web API和Lambda验证无服务器Web请求?

[英]How to authenticate serverless web request using AWS Web API and Lambda?

Little background info, 小背景信息,

I have built an interactive website where users can upload images to S3. 我建立了一个互动网站,用户可以将图像上传到S3。 I built it so the image upload goes right from the browser to AWS S3 using a signed request ( python django backend ). 我构建了它,因此使用签名请求(python django后端)将图像上传从浏览器直接传送到AWS S3。

Now the issue is, the users wish to be able to rotate the image. 现在的问题是,用户希望能够旋转图像。 I Similarly I would like this set up so the user's request goes straight from the browser. 我同样我希望这样设置,以便用户的请求直接来自浏览器。 I built an AWS Lambda function and attached it to a web api, which will accept POST requests. 我构建了一个AWS Lambda函数并将其附加到web api,它将接受POST请求。 I have been testing and I finally got it working. 我一直在测试,我终于开始工作了。 The function takes 2 inputs, key , and rotate_direction , which are passed as POST variables to the web api. 该函数接受2个输入, keyrotate_direction ,它们作为POST变量传递给web api。 They come into the python function in the event variable. 它们进入event变量的python函数。 Here is the simple Lambda function: 这是简单的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' }

Everything is working. 一切正常。 So now my issue is how to enforce some kind of authentication for this system? 那么现在我的问题是如何为这个系统强制执行某种身份验证? The ownership details about each image reside on the django web server. 每个映像的所有权详细信息都驻留在django Web服务器上。 While all the images are considered "public", I wish to enforce that only the owner of each image is allowed to rotate their own images. 虽然所有图像都被视为“公开”,但我希望强制只允许每个图像的所有者旋转自己的图像。

With this project I have been venturing into new territory by making content requests right from the browser. 通过这个项目,我一直在通过浏览器发出内容请求进入新的领域。 I could understand how I could control access by only making the POST requests from the web server, where I could validate the ownership of the images. 我可以理解如何通过仅从Web服务器发出POST请求来控制访问,在那里我可以验证图像的所有权。 Would it still be possible having the request come from the browser? 是否仍然可以通过浏览器提出请求?

TL;DR Solution: create a Cognito Identity Pool, assign policy users can only upload files prefixed by their Identity ID. TL; DR解决方案:创建一个Cognito Identity Pool,分配策略用户只能上传以其身份ID为前缀的文件。

If I understand your question correctly, you want to setup a way for an image stored on S3 to be viewable by public , yet only editable by the user who uploaded it . 如果我正确理解您的问题,您希望为存储在S3上的图像设置一种方式,供公众查看 ,但只能由上传它的用户编辑 Actually, you can verify file ownership, rotate the image and upload the rotated image to S3 all in the browser without going through a Lambda function. 实际上,您可以在浏览器中验证文件所有权,旋转图像并将旋转的图像上传到S3,而无需通过Lambda函数。

Step 1: Create a Cognito User Pool to create a user directory. 步骤1:创建Cognito用户池以创建用户目录。 If you already have a user login/sign up authentication system, you could skip this step. 如果您已拥有用户登录/注册身份验证系统,则可以跳过此步骤。

Step 2: Create a Cognito Identify Pool to enable federated identity, so your users can get a temporary AWS credential from the Identity Pool, and use it to upload files to S3 without going through your server/lambda. 步骤2:创建Cognito Identify Pool以启用联合身份,以便您的用户可以从Identity Pool获取临时AWS凭证,并使用它将文件上载到S3而无需通过您的server / lambda。

Step 3: When creating the Cognito Identity Pool, you can define a policy on what S3 resources a user is allowed to access. 步骤3:创建Cognito Identity Pool时,您可以定义允许用户访问哪些S3资源的策略。 Here is a sample policy 这是一个示例政策

{
  "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}*"
      ]
    }
  ]
}

Note the second block assigns "S3:GetObject" to all files in your S3 bucket; 注意第二个块将“S3:GetObject”分配给S3存储桶中的所有文件; and the third block assigns "S3:PutObject" to ONLY FILES prefixed with the user's Cognito Identity ID. 第三个块将“S3:PutObject”分配给以用户的Cognito Identity ID为前缀的ONLY FILES。

Step 4: In frontend JS, get a temporary credential from Cognito Identity Pool 第4步:在前端JS中,从Cognito Identity Pool获取临时凭证

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();
    })
  ));
}

Step 5: Upload files to S3 with the credential, prefix the file name with the user's Cognito Identity ID. 步骤5:使用凭证将文件上载到S3,使用用户的Cognito Identity 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}`);
    })
  ));
}

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

相关问题 如何配置serverless.yml或AWS API网关或AWS Lambda处理程序以从POST请求读取request.header - How to configure serverless.yml or AWS API gateway or AWS lambda handler to read request.headers from POST request 如何在AWS Lambda上的无服务器应用程序中存储和使用HTML模板(使用AWS SAM)? - How to store and use HTML templates in serverless application on AWS Lambda (using AWS SAM)? Python AWS Lambda Web抓取工具 - Python AWS Lambda Web scraper 如何使用urllib2向Coverity Web API发送请求? - How to send a request to Coverity web api using urllib2? 在 python 中使用 AWS Lambda 向外部 API 发送 Post 请求 - Send Post request to an external API using AWS Lambda in python 如何使用 Ansible 将 AWS API 网关集成请求正确设置为 lambda 函数? - How to set AWS API gateway integration request to lambda function correctly using Ansible? 如何使用 Python 使用 JSON 文件正确执行 AWS Lambda API Post 请求 - How to properly do an AWS Lambda API Post Request with JSON file using Python 如何使用无服务器将 librosa (python lib) 添加到 aws lambda - How do I add librosa (python lib) to aws lambda using serverless 使用无服务器框架为 AWS Lambda 构建和使用本地包 - Build and use local package for AWS Lambda using serverless framework 使用无服务器框架将 Python package 部署到 AWS lambda 时出错 - Error deploying Python package to AWS lambda using Serverless framework
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM