【问题标题】:How to create a web form allowing authenticated users to upload files to S3?如何创建允许经过身份验证的用户将文件上传到 S3 的 Web 表单?
【发布时间】:2019-01-17 23:05:13
【问题描述】:

如何创建一个接受用户输入并将授权用户上传到 AWS 的图像文件存储的 Web 应用程序?有权上传文件的用户是 Web 用户,而不是 AWS IAM 用户。理想情况下,他们从带有代表此授权用户的查询参数的 url 访问此 Web。我正在考虑在 S3 中创建一个静态网站,将用户输入和图像文件存储在 S3 存储桶子文件夹中。每个授权用户仅对其自己的子文件夹具有读\写权限。但是,由于 S3 是无服务器的,我需要有关如何使用 lambda 和 API Gateway 或其他 AWS 服务来处理来自 Web 表单的请求并将文件上传到 S3 的详细信息。看来我可以使用 Drupal 或 WordPress Webform 插件来创建 webform 并将文件上传到 S3。在这种情况下,我需要 Drupal\WordPress 的 EC2 实例,而不是 S3 静态网站。我正在寻找有关该项目最佳架构的建议。欢迎任何教程、说明和示例代码。提前致谢。

【问题讨论】:

    标签: amazon-web-services amazon-s3 amazon-ec2


    【解决方案1】:

    如果您需要您的用户对您的应用程序进行身份验证,那么您需要将他们的凭据存储在某个数据库(即 DynamoDB)中。为此,您需要一些将执行身份验证过程的后端服务 - 将用户的凭据存储在数据库中,从数据库中检索用户的凭据,验证凭据。

    您可以编写自己的服务器,也可以通过 API Gateway 使用无服务器 Lambda 方法。但这里重要的是你需要有这个后端逻辑。仅使用静态 S3 网络托管是无法实现的(但它可以是整个系统的一部分)。

    AWS IAM 在此场景中仅用于创建允许服务 - EC2/Lambda - 对 S3 存储桶和 DynamoDB 执行读/写操作的角色。您的应用程序用户与 IAM 无关。

    应用程序的流程是:

    1. 用户注册您的应用程序
    2. 您的应用程序在数据库中创建一条记录,其中包含用户凭据和指向该用户唯一的某些 S3 资源的指针
    3. 当登录用户尝试上传图片时,数据会发送到您的应用程序
    4. 您的应用程序从 DB 中检索请求者的记录,查找 S3 指针并将图像上传到那里

    从架构的角度来看,在设计此类系统时需要考虑很多因素 - 流量、对 CI-CD 的要求等等。

    如果您想要一些非常简单的东西,那么您可以使用 API Gateway 创建您的 REST API,其中每个资源方法都将分配有适当的 lambda 函数(这些函数将执行上述逻辑)。您可以使用自定义身份验证流程,也可以利用 AWS Congnito。最后,您可以在 S3 上托管您的网页(假设它在此设置中是静态的),对您的 API 网关进行 ajax 调用。

    【讨论】:

    • 实际上,有一种方法可以在没有服务器或 lambda 函数的情况下实现这一点,只需使用 Cognito 和 AWS SDK for Javascript
    • 非常感谢您的反馈。对于这个项目,网络用户将通过他们在注册时提供的密码登录到这个应用程序,而不是使用他们的 OpenID 凭据。如何以编程方式检索存储在一个 EC2 WordPress 实例中的 mySQL DB 中的用户密码,并使用它来验证用户登录到允许用户将文件上传到其自己的 S3 子文件夹的应用程序?我是 AWS 的新手,非常感谢任何使其工作的示例代码或教程。
    【解决方案2】:

    这个想法是使用AWS Cognito。 Cognito Federated Identities 允许向经过身份验证的用户提供临时访问令牌。它与 Login With Amazon、Facebook、Google 或任何使用 OpenID 或 SAML 的平台集成。

    您的单页 Web 应用可以通过 AWS SDK for Javascript 访问 Cognito。

    所以我们的想法是在您的网页上提出身份验证。我正在使用Login with Amazon 或类似的。您还可以选择使用 Cognito 用户池(Cognito 存储用户配置文件并提供登录、注册、密码恢复等功能)

    一旦通过身份验证,您的 Javascript 代码就可以在 AWS.Config.credentials 上调用 refresh(),并传递从上述身份验证步骤收到的访问令牌。 refresh() 将依次调用 Cognito 的 API 以接收临时和用户特定的访问令牌。

    function initializeCognito(access_token) {
    
                return new Promise((resolve, reject) => {
    
                    // Initialize the Amazon Cognito credentials provider
                    AWS.config.region = 'us-east-1'; // Region
                    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
                        IdentityPoolId: 'us-east-1:cognito pool id', // < -- insert your cognito pool ID here
                        Logins: {
                            'www.amazon.com': access_token
                        }
                    });
                    console.log("Calling Cognito to refresh AWS Credentials");
    
                    // get AWS credentials
                    AWS.config.credentials.refresh(function (err) {
    
                        if (err) {
                            console.log("Error when calling Cognito");
                            console.log(err, err.stack);
                            reject(err);
                        } else {
                            console.log("Cognito credenials received ");
                            resolve(AWS.config.credentials);
                        }
                    });
                });
            }
    

    完成此操作后,您的其余代码可以调用任何 AWS 开发工具包 API 来调用后端服务,包括 S3、DynamoDB ...

    这是 DynamoDB 的示例:

    
            function insertIntoDDB(profile, text) {
                return new Promise((resolve, reject) => {
                    var dynamodb = new AWS.DynamoDB();
                    var params = {
                        Item: {
                            "cognitoid": { //hash key
                                S: profile.cognito_id
                            },
                            "userid": {
                                S: profile.user_id
                            },
                            "text": {
                                S: text
                            },
                            "creationtime": { // sort key 
                                N: Math.round(new Date() / 1000).toString()
                            },
                            "expirationtime": { // 1 month later ?
                                N: (Math.round(new Date() / 1000) + (1 * 60 * 60 * 24 * 30)).toString()
                            }
                        },
                        TableName: "my_table"
                    };
                    dynamodb.putItem(params, (err, data) => {
                        if (err) {
                            console.log("Error when calling DynamoDB");
                            console.log(err, err.stack); // an error occurred
                            reject(err);
                        } else {
                            // console.log(data); // successful response
                            resolve(data);
                        }
                    });
                });
            }
    

    AWS SDK 为您管理身份验证,如您所见,传递访问密钥(秘密密钥)不涉及任何代码。访问密钥和秘密密钥由 Cognito 为该特定用户生成并存储在 AWS.config.credential 对象中。访问密钥和密钥的范围和时间是有限的。

    为了限制范围,您可以在 Cognito 控制台上定义 IAM 角色以与经过身份验证的用户关联,授予他们仅访问您的代码所需的服务和操作的权限。此外,S3 和 DynamoDB 允许 fine grained permission,允许您限制对存储桶中的特定键(文件夹)或表中的行的写入访问。

    您可以在 https://alexademo.ninja/skills/myteacher/index.html 看到这项技术的实际应用。我写这篇文章是为了与“My Pronunciation Teacher”Alexa Skill 一起使用。

    还有一个完整的教程将向您展示如何使用适用于 JavaScript 的 AWS 开发工具包将图片从 Web 表单上传到 AWS Documentation 中的 S3。此代码还利用了 Cognito,它非常接近您想要实现的目标。

    使用这种技术,不需要后端服务器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-08
      • 2019-11-18
      • 2021-01-06
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 2016-01-17
      相关资源
      最近更新 更多