使用AWS和S3存储桶的静态站点的基本用户身份验证

Gid*_*n B 0 authentication amazon-s3 bucket amazon-web-services amazon-cloudfront

我希望将基本用户身份验证添加到我将在AWS上使用的静态站点,以便只有那些将提供给这些用户的用户名和密码正确的用户才能访问该站点。我找到了s3auth,这似乎正是我要寻找的东西,但是,我想知道是否需要以某种方式为除index.html之外的页面设置授权。例如,我有3个页面,分别是index,about和contact.html,而没有对about.html进行身份验证的设置是什么阻止了个人通过www.mywebsite.com/about.html直接访问该网站?我更希望获得澄清或任何人可以提供的任何资源来解释这一点!

谢谢您的帮助!

hep*_*ump 7

这是Lambda @ Edge的完美用法。

由于您在S3上托管静态站点,因此可以使用AWS的内容分发网络CloudFront轻松,非常经济(便士)为您的站点添加一些非常好的功能,以将站点提供给站点。您可以在此处了解如何使用CloudFront(包括100%免费SSL)在S3上设置站点托管。

在部署CloudFront发行版时,您将有一些时间来设置Lambda,并将其用于执行基本用户身份验证。如果这是您第一次创建Lambda或创建供@Edge使用的Lambda,则过程将变得非常复杂,但是如果您按照下面的逐步说明进行操作,则将无限制地进行无服务器基本身份验证在不到10分钟的时间内即可扩展。我将为此使用us-east-1,并且很重要的一点是要知道,如果您使用的是Lambda @ Edge,则应在us-east-1中编写函数,并将它们与CloudFront发行版关联时,将自动全局复制。让我们开始...

  1. 转到AWS控制台中的Lambda,然后单击“ 创建函数
  2. 从头开始创建Lambda并命名
  3. 将运行时设置为Node.js 8.10
  4. 通过选择“选择或创建执行角色”,为Lambda授予一些权限
  5. 给角色起个名字
  6. 从策略模板中选择“基本Lambda @ Edge权限(用于CloudFront触发器)”
  7. 点击“创建功能”
  8. 创建Lambda后,请使用以下代码并将其粘贴到该Function Code部分的index.js文件中-您可以通过更改authUser和authPass变量来更新要使用的用户名和密码:
'use strict';
exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // Configure authentication
    const authUser = 'user';
    const authPass = 'pass';

    // Construct the Basic Auth string
    const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');

    // Require Basic authentication
    if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
            status: '401',
            statusDescription: 'Unauthorized',
            body: body,
            headers: {
                'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
            },
        };
        callback(null, response);
    }

    // Continue request processing if authentication passed
    callback(null, request);
};

Run Code Online (Sandbox Code Playgroud)
  1. 点击右上角的“保存”。
  2. 现在,您的Lambda已保存,可以连接到CloudFront发行版了。在上方菜单中,选择操作->部署到Lambda @ Edge。
  3. 在出现的模式中,从下拉菜单中选择您先前创建的CloudFront分配,将“缓存行为”保留为*,对于CloudFront事件,将其更改为“查看器请求”,最后选择/勾选“包括正文”。选择/勾选确认部署到Lambda @ Edge,然后单击“部署”。

现在,您等待。在所有区域和边缘位置复制Lambda @ Edge需要几分钟(15-20)。转到CloudFront监视功能的部署。当您的CloudFront分布状态显示为“已部署”时,您的Lambda @ Edge功能就可以使用了。

  • `callback(null, response);` 前面应该有 `return` 否则这段代码会在这种情况下调用回调两次,这可能很难检测但仍然有负面影响。我希望节点进程被终止并透明地重新生成,导致下一次调用碰到同一个容器......如果不是容器破坏......由于可能发生的异常(但可能不会被记录,或者可能在下一次调用期间抛出)。 (3认同)
  • 如果您在步骤 10 中没有看到“部署到 Lambda@Edge”选项,请确保您位于 us-east-1 区域。[请参阅 aws 文档](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html) (2认同)

hen*_*eck 5

到目前为止,这也可以通过我更喜欢的 CloudFront 函数实现,因为它进一步降低了复杂性(使用 Lambda 已经不太复杂了)。这是我刚刚所做的事情的记录...

基本上需要做三件事:

  1. 创建一个 CloudFront 函数以将基本身份验证添加到请求中。
  2. 在几个地方正确配置 CloudFront 发行版的起源。
  3. 激活CloudFront功能。就是这样,没有其他特别的花里胡哨的东西。这是我所做的:

首先,转到 CloudFront,然后单击左侧的“函数”,使用您选择的名称创建一个新函数(不需要区域等),然后添加以下内容作为该函数的代码:

function handler(event) {

    var user = "myuser";
    var pass = "mypassword";

    function encodeToBase64(str) {
        var chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        for (
            // initialize result and counter
            var block, charCode, idx = 0, map = chars, output = "";
            // if the next str index does not exist:
            //   change the mapping table to "="
            //   check if d has no fractional digits
            str.charAt(idx | 0) || ((map = "="), idx % 1);
            // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
            output += map.charAt(63 & (block >> (8 - (idx % 1) * 8)))
        ) {
        charCode = str.charCodeAt((idx += 3 / 4));
        if (charCode > 0xff) {
            throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."
        );
        }
        block = (block << 8) | charCode;
      }
      return output;
    }


    var requiredBasicAuth = "Basic " + encodeToBase64(`${user}:${pass}`);
    var match = false;
    if (event.request.headers.authorization) {
        if (event.request.headers.authorization.value === requiredBasicAuth) {
            match = true;
        }
    }

    if (!match) {
      return {
        statusCode: 401,
        statusDescription: "Unauthorized",
        headers: {
          "www-authenticate": { value: "Basic" },
        },
      };
    } 

    return event.request;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以直接在 UI 上进行测试,假设它可以工作,并假设您已经自定义了用户名和密码,则发布该功能。

请注意,我在互联网上找到了上述函数的各个部分,因此这不是我自己的代码(除了将其拼凑在一起之外)。我希望我仍然能找到来源,这样我就可以在这里引用它们,但我再也找不到它们了。不过还是要归功于创作者!:-)

接下来,打开您的 CloudFront 分配并执行以下操作:

  1. 确保源中的 S3 存储桶配置为 REST 端点而不是网站端点,即它必须以 结尾且主机名中.s3.amazonaws.com不包含该单词。website

  2. 另外,在 Origin 设置中的“S3 存储桶访问”下,选择“是使用 OAI(存储桶只能限制对 CloudFront 的访问)”。在下面的设置中,单击“创建 OAI”以创建一个新的 OAI(除非您已有 OAI 并且知道自己在做什么)。并选择“是,更新存储桶策略”以允许 AWS 向您的 OAI 添加必要的权限。

  3. 最后,打开 CloudFront 发行版的行为并滚动到底部。在“函数关联”下,对于“查看者请求”,选择“CloudFront 函数”,然后选择您新创建的 CloudFront 函数。保存您的更改。

应该就是这样。如果运气好的话,只需几分钟(我知道实际上更多),尤其是一旦全部设置完毕,就不会增加复杂性。