Varnish和ESI HTTP AUTH

时间:2013-07-17 16:00:34

标签: http authentication symfony varnish esi

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

我有一个使用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身份验证效果很好。

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

1 个答案:

答案 0 :(得分:4)

var in中的ESI不像浏览器中的iframe或链接标记,因为它不会连接到您提供的任何URL。 ESI只是在varnish中启动一个新请求并完成工作流程(vcl_recv等)。

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

完成你想要做的事情的方法是(在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”的虚拟主机,则可能还需要设置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片段本身将始终使用客户端的授权头传递给后端。