将Cookie传递给CloudFront来源但阻止缓存

tot*_*tas 5 amazon-web-services symfony amazon-cloudfront aws-lambda foshttpcachebundle

我在Symfony Web应用程序前面使用CloudFront作为缓存.要根据用户的角色(admin,customer,...)获取缓存,我会在Lambda @ Edge Viewer请求触发器中生成基于用户角色的哈希.我将该哈希作为请求标头传递给我的原点X-User-Context-Hash.

我现在的问题是我需要将PHPSESSIDcookie 传递给我的源,以获得正确的缓存响应,但我不想将缓存基于值的PHPSESSID.我只需要根据X-User-Context-Hash我的会话cookie 的值而不是我的缓存响应.

下面的图片应该详细解释我的问题

有没有可能实现这一目标?

非常感谢任何帮助.

在此输入图像描述

这是我的Lambda @ Edge Viewer请求触发器:

'use strict';

function parseCookies(headers) {
    const parsedCookie = {};
    if (headers.cookie) {

        console.log(`${headers.cookie[0].value}`);

        headers.cookie[0].value.split(';').forEach((cookie) => {
            if (cookie) {
                const parts = cookie.split('=');
                parsedCookie[parts[0].trim()] = parts[1].trim();
            }
        });
    }
    return parsedCookie;
}

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    const https = require('https');

    // Read session cookie
    const parsedCookies = parseCookies(headers);
    let cookie = '';
    if (parsedCookies) {
        if(parsedCookies['PHPSESSID']) {
            cookie = `PHPSESSID=${parsedCookies['PHPSESSID']}`;
        }
    }

    console.log(`Cookie: ${cookie}`);

    // Send request to origin host at /_fos_user_context_hash
    // passing the original session cookie
    const options = {
        hostname: `${request.headers.host[0].value}`,
        port: 443,
        path: '/_fos_user_context_hash',
        method: 'HEAD',
        headers: {
            'Cookie': cookie, 
            'Accept': 'application/vnd.fos.user-context-hash',
            'Vary' : 'Cookie'
        }
    };

    const req = https.request(options, (res) => {
      console.log('statusCode:', res.statusCode);
      console.log('headers:', res.headers);

      // Read the X-User-Context-Hash from the hash endpoint
      const headerName = 'X-User-Context-Hash';
      let hash = 'anonymous';

      if (res.headers[headerName.toLowerCase()]) {
        hash = res.headers[headerName.toLowerCase()];
      }

      // Append X-User-Context-Hash before passing request on to CF
      request.headers[headerName.toLowerCase()] = [{ key: headerName, value: hash }];  

      callback(null, request);

    }).on('error', (e) => {
      console.error(e);
      // Forward request anyway
      callback(null, request);
    });

    req.end();
}


;
Run Code Online (Sandbox Code Playgroud)

Ser*_*tin 8

AWS 最近引入了缓存和源请求策略,允许更多定制。

现在,您可以通过设置适当的缓存策略并设置源请求策略以仅转发必要的数据,基于 cookie/查询字符串参数的“除所有”列表来设置缓存行为:

在此输入图像描述


tot*_*tas 6

这是我最终解决了我的问题:

CloudFront行为

我配置的行为没有任何的cookie转发到原点,但基于首只缓存HostX-User-Context-Hash(见截图).

截图CloudFront行为

下图解释了我的lambda @ edge过程: lambda @ edge进程

  1. 在"查看器请求"触发器中,我读取了名为的基于用户的cookie PHPSESSID,REMEMBERME并通过X-Session-Cookies标头传递这些值.
  2. 如果有对我的请求的URL匹配和给定HostX-User-Context-Hash头,云前返回缓存的项目,并在这里停止.
  3. 如果没有匹配则触发"Origin Request"触发器.当该事件触发时,X-Session-Cookies可以使用自定义标头.所以我从X-Session-Cookies标题中取值并将值设置request.headers.cookie为该值.此步骤确保在页面缓存之前将cookie PHPSESSIDREMEMBERMEcookie都传递到源.

我的Lambda @ Edge功能:

查看者请求触发器:

'use strict';

function parseCookies(headers) {
    const parsedCookie = {};
    if (headers.cookie) {

        console.log(`${headers.cookie[0].value}`);

        headers.cookie[0].value.split(';').forEach((cookie) => {
            if (cookie) {
                const parts = cookie.split('=');
                parsedCookie[parts[0].trim()] = parts[1].trim();
            }
        });
    }
    return parsedCookie;
}

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    const https = require('https');

    let sessionId = '';

    // Read session cookie
    const parsedCookies = parseCookies(headers);
    let cookie = '';
    if (parsedCookies) {
        if(parsedCookies['PHPSESSID']) {
            cookie = `PHPSESSID=${parsedCookies['PHPSESSID']}`;
        }
        if(parsedCookies['REMEMBERME']) {
            if (cookie.length > 0) {
                cookie += ';';
            }
            cookie += `REMEMBERME=${parsedCookies['REMEMBERME']}`;
        }
    }

    console.log(`Cookie: ${cookie}`);

    // Send request to origin host at /_fos_user_context_hash
    // passing the original session cookie
    const options = {
        hostname: `${request.headers.host[0].value}`,
        port: 443,
        path: '/_fos_user_context_hash',
        method: 'HEAD',
        headers: {
            'Cookie': cookie, 
            'Accept': 'application/vnd.fos.user-context-hash',
            'Vary' : 'Cookie'
        }
    };

    const req = https.request(options, (res) => {
      console.log('statusCode:', res.statusCode);
      console.log('headers:', res.headers);

      // Read the X-User-Context-Hash from the hash endpoint
      const headerName = 'X-User-Context-Hash';
      let hash = 'anonymous';

      if (res.headers[headerName.toLowerCase()]) {
        hash = res.headers[headerName.toLowerCase()];
      }

      // Append X-User-Context-Hash before passing request on to CF
      request.headers[headerName.toLowerCase()] = [{ key: headerName, value: hash }];

      const sessionHeaderName = 'X-Session-Cookies';
      request.headers[sessionHeaderName.toLowerCase()] = [{ key: sessionHeaderName, value: cookie }];  

      callback(null, request);

    }).on('error', (e) => {
      console.error(e);
      // Forward request anyway
      callback(null, request);
    });

    req.end();
}


;
Run Code Online (Sandbox Code Playgroud)

原始请求触发器:

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    const sessionHeaderName = 'X-Session-Cookies';

    let cookie = '';
    if (request.headers[sessionHeaderName.toLowerCase()]) {
        console.log(request.headers[sessionHeaderName.toLowerCase()]);
        cookie = request.headers[sessionHeaderName.toLowerCase()][0].value;
    }

    request.headers.cookie = [{ key : 'Cookie', value : cookie }];

    callback(null, request);
};
Run Code Online (Sandbox Code Playgroud)


Mic*_*bot 3

根本问题:

如果您将 CloudFront 配置为将 cookie 转发到您的源,CloudFront 会根据 cookie 值进行缓存。即使您的源忽略请求中的 cookie 值,这也是如此......

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Cookies.html

这是设计使然。您转发的 Cookie 始终是缓存键的一部分。

没有干净/简单/明显的解决方法。

您可以将会话 cookie 添加到查看器请求触发器中的查询字符串中,并将该参数配置为转发但不用于缓存,然后您的源需要在那里找到它并将其解释为 cookie。与 cookie 不同,查询字符串参数可以配置为转发,但不能配置为缓存。

您可以将实际请求中的 cookie 替换为虚拟/占位符值(每个用户类一个),以便将其转发到源并用于缓存,然后使用查看器响应触发器来阻止Set-Cookie来自来源(或缓存),以免将该神奇 cookie 暴露给任何查看者。

不过,实际上,听起来好像您可能试图在一个地方解决一个真正需要在另一个地方解决的问题。您的应用程序在设计上存在限制,对于某些资源来说,缓存不友好。这些资源需要设计为以缓存友好的方式进行交互,当访问资源需要对用户、角色、组、权限等进行身份验证时,这当然是一个非常棘手的命题。