2013-07-16 27 views
1

我有一個私人的Intranet樣式的網站,每個人都必須在看到任何內容之前登錄。一旦他們登錄,每個頁面都是相同的 - 所以我希望這些頁面緩存在Varnish中,但仍需要快速的用戶訪問權限檢查。Varnish驗證緩存的請求

所以我想這樣做,我會在我的VCL文件中創建一個規則,將每個傳入請求重寫爲一個文件。這個文件沒有被緩存,並檢查用戶是否有效,如果是的話,它打印esi包括緩存頁面。

這一切都可以,除了識別緩存頁面的第二個請求被認證。我正在考慮添加一個查詢字符串到請求,並檢查。或者,也許有一種方法可以檢查是否通過esi:include進行了請求。 也許我以錯誤的方式接近這個?

有什麼建議嗎?

回答

0

如果你只需要基本身份驗證支票上http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/描述你可以使用普通的HTTP認證:

用戶:通過

$echo -n "foo:bar" | base64 

VCL

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是否存在。

1

如果您不想在URL中使用具有身份驗證令牌的身份驗證請求,則可以檢查req.esi_level並確保其需要登錄的資源大於0。

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

需要注意的是,你需要阻止除漆一切訪問你的後臺 - 你很可能就是這麼做的,但值得注意的。

+0

謝謝,這是好的瞭解req.esi_level。如果你使用esi來做其他事情,會不會有另外一個警告呢? –

+1

我結束了與基於此解決方案:http://joshwaihi.com/content/authenticated-page-caching-varnish-drupal其中的請求被轉移到另一個未緩存的網址,並返回一個頭,確定認證。該請求然後在vcl內重新啓動,頁面可以從緩存中提供。 –

+0

這不會「破壞」其他任何東西,因爲只有當客戶端直接請求/ private/*時纔會進行干預 - 這是您聲稱您試圖阻止的內容。所有其他場景將不匹配if語句。如果您的業務規則更復雜,則需要更新VCL以匹配。我很高興你找到了另一種解決方案,但對於你正在嘗試做的事情來說,它看起來相當複雜。 –

0

這是我在開發環境中嘗試過的,我不確定我們是否會在生產中使用它。

光油配置

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    */ 
    } 

} 

然後在Apache中我重定向頁面是通過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"); 
}