2

我对这个问题很迷茫,我不知道问题出在哪里,所以,我希望你能帮助我。

我有一个带有 symfony 的 HTTP BASIC 身份验证,我正在尝试访问一个受此身份验证保护的 URL,并在 Drupal 页面中带有一个标签。每个请求都发送到 Varnish

我在网址中提供用户名和密码,如下所示:

<esi:include src="http://admin:adminpass@api.dev:8081/app.php/next"/>

在我的清漆配置文件中,我只有 auth.http 的那几行:

if (req.http.Authorization) {
  return (pass);
}

我的 Symfony 后端在没有 http 身份验证的情况下运行良好,并且在没有 Varnish 和 esi 标签的情况下,http 身份验证运行良好。

如果有人知道这个问题,请告诉我,即使它是错误的 =)

4

1 回答 1

5

清漆中的 ESI 不像浏览器中的 iframe 或链接标签那样工作,因为它不会连接到您提供的任何 url。ESI 只是在 varnish 中启动一个新请求并通过工作流(vcl_recv 等)。

您期望 varnish 像 http 客户端一样工作,解析 url,设置授权标头,将主机标头设置为 api.dev:8081 并启动新的 http 连接/请求,但它不会。在这种情况下,我的猜测是它会启动一个新的 req,其中 req.url 设置为 /app.php/next 继承父资源请求的标头(包含 esi 标签),或者可能只是完全忽略 esi 标签。

完成您想做的事情的方法是(在 vcl_recv 中):

if (req.esi_level > 0 && req.url == "/app.php/next") {
     set req.http.Authorization = "BASIC [base64 encoded admin:adminpass]"
     return (pass);
}

然后esi标签应该看起来像<esi:include src="/app.php/next" />

如果您需要 ESI 请求访问不同的后端服务器,则需要将该服务器添加为不同的命名后端:

backend authorization_needed {
   .host = "api.dev";
   .port = "8081";
}

并在 vcl_recv 中,告诉 varnish 将其用于 esi 请求:

if (req.esi_level > 0 && req.url == "/app.php/next") {
   set req.http.Authorization = "BASIC [base64 encoded admin:adminpass]"
   set req.backend = authorization_needed;
   return (pass);
}

如果后端响应与“api.dev”不同的虚拟主机,您可能还需要在 if 块中设置 req.http.Host。

更新:

由于基本授权来自客户端,并且当 req.http.Authorization 存在时您正在调用 return(pass),varnish 不会 ESI 处理这些页面。您必须在通过时不调用的 vcl_fetch() 中显式启用 esi。

因此,要通过 ESI 片段而不是父页面的授权,请更改 vcl_rev:

if (req.http.Authorization && req.esi_level == 0) {
    set req.http.X-Esi-Authorization = req.http.Authorization;
    unset req.http.Authorization;
}
else if (req.http.X-Esi-Authorization && req.esi_level > 0 ) {
    set req.http.Authorization = req.http.X-Esi-Authorization;
    return (pass);
}

并添加到 vcl_fetch:

if (req.http.X-Esi-Authorization) {
    set beresp.do_esi = true;
}

最终效果是父响应是可缓存的并且将处理 esi,esi 片段本身将始终与客户端的授权标头一起传递给后端。

于 2013-07-17T16:55:27.360 回答