Varnish аутентифицирует кешированный запрос

У меня есть частный веб-сайт в стиле интрасети, где каждый должен войти в систему, прежде чем увидеть какой-либо контент. После того, как они вошли в систему, каждая страница одинакова, поэтому я хочу, чтобы эти страницы кэшировались в Varnish, но все же с быстрой проверкой доступа пользователя.

Поэтому я думал сделать это, я бы создал правило в своем файле VCL, которое перезаписывает каждый входящий запрос в один файл. Этот файл не кэшируется и проверяет, действителен ли пользователь, если это так, он печатает esi include кэшированной страницы.

Все в порядке, за исключением того, что второй запрос кэшированной страницы идентифицируется как аутентифицированный. Я думал добавить строку запроса к запросу и проверить это. Или, может быть, есть способ проверить, был ли сделан запрос через esi:include. Может быть, я неправильно к этому отношусь?

Какие-либо предложения?


person leon.nk    schedule 16.07.2013    source источник


Ответы (3)


Если вы не хотите использовать аутентифицированный запрос с токеном аутентификации в URL-адресе, вы можете проверить req.esi_level и убедиться, что он больше 0 для ресурсов, требующих входа в систему.

if (req.esi_level == 0 && req.url ~ "^/private/.*" ) {
    error (403);
}

Предупреждение заключается в том, что вам нужно запретить доступ к вашему бэкенду всем, кроме лака — что вы, вероятно, и так делали, но это стоит отметить.

person Johnny C    schedule 17.07.2013
comment
Спасибо, приятно узнать о req.esi_level. Не будет ли еще одно предостережение в том, что это сломается, если вы используете esi для чего-то еще? - person leon.nk; 09.08.2013
comment
В итоге я выбрал решение, основанное на этом: joshwaihi.com/content/authenticated -page-caching-varnish-drupal, где запрос перенаправляется на другой URL-адрес, который не кэшируется, и возвращает заголовок, определяющий аутентификацию. Затем запрос перезапускается в vcl, и страница может обслуживаться из кеша. - person leon.nk; 09.08.2013
comment
Это ничего не сломает, так как вмешивается только тогда, когда клиент запрашивает /private/* напрямую - это то, что вы заявили, что пытались предотвратить. Все остальные сценарии не будут соответствовать оператору if. Если ваши бизнес-правила более сложны, вам потребуется обновить VCL, чтобы они соответствовали. Я рад, что вы нашли другое решение, но оно кажется довольно сложным для того, что вы пытаетесь сделать имхо. - person Johnny C; 09.08.2013
comment
Ну, есть еще несколько требований, которые я не упомянул в своем первоначальном посте. Одним из них было то, что страница 403 должна обслуживаться Apache. Кроме того, решение хорошо сочетается с приложением (которое уже создано) и требует минимальной модификации. - person leon.nk; 15.08.2013

Если вам нужна только базовая проверка аутентификации, вы можете использовать обычную HTTP-аутентификацию, как описано в http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/ :

Пользователь: пройти

$echo -n "foo:bar" | base64

ВКЛ

sub vcl_fetch {
# ...
  if (! req.http.Authorization ~ "Basic Zm9vOmJhcgo=")
  {
    error 401 "Restricted";
  }
# ...
}

sub vcl_error {
# ...
  if (obj.status == 401) {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    set obj.http.WWW-Authenticate = "Basic realm=Secured";
    synthetic {" 
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
    <HTML>
    <HEAD>
    <TITLE>Error</TITLE>
    <META HTTP-EQUIV='Content-Type' CONTENT='text/html;'>
    </HEAD>
    <BODY><H1>401 Unauthorized (varnish)</H1></BODY>
    </HTML>
    "};
    return (deliver);
  }
# ...
}

Если вы предпочитаете свой текущий подход, вы всегда можете установить файл cookie при первом запросе, а затем проверить, присутствует ли файл cookie.

person NITEMAN    schedule 16.07.2013

Вот что я пробовал в среде разработки, я еще не уверен, будем ли мы использовать это в производстве.

Лак конфиг

probe checkslash {
    .url = "/robots.txt";
    .interval = 500s;
    .timeout = 10s;
}    

include "backends.vcl";

/** generic config from here down */
sub vcl_recv{

    /* if the drupals are down, this is how long we cache for */
    set req.grace = 6h;

    /* Make sure we direct 443 traffic to the secure drupal */
    if (server.port == 443 ) {
      set req.backend = drpau_ssl_director;

   } else {
      /* port 80 traffic goes to the correct LB */
      set req.backend = drpau_director;
    }
 # just pass through non-page files, and the login page
   if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js|htc|ejs)(\?.*)?$") {
       } else if (req.url ~ "(?i)(sites/default/files)|(js/)|(/login)" ) { 
    } else if (req.esi_level == 0 ) {
     # pass regular pages to a spoecial url
     set req.url = "/esi" + req.url;
   }
    return (lookup);
}



sub vcl_fetch {

 if (req.url ~ "/esi/" && req.esi_level == 0 ) {
       set beresp.do_esi = true; /* Do ESI processing               */ 
    }

}

Затем в апаче перенаправляю все запросы страниц, которые приходят через префикс esi

RewriteRule ^esi/(.*)$ test.php [L]

и тестовый php

<?php 
define('DRUPAL_ROOT', getcwd());
// We prepare only a minimal bootstrap.
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
global $user;
$roles = user_roles();

if (in_array('anonymous user', $user->roles)) {
  $uri = preg_replace('#^/esi#', '', $_SERVER[REQUEST_URI]);
  echo "<esi:include src=\"http://$_SERVER[SERVER_NAME]$uri\"/>";
} else {
    header("Location: https://$_SERVER[SERVER_NAME]/login");
}
person Sean Burlington    schedule 15.10.2013