2

Spring Securityのremember-me機能をVarnishで動作させようとしていますが、これは非常に難しいようです。通常のログインでは簡単です。j_spring_security_checkURLのキャッシュをバイパスするようにVarnishを設定するだけですが、remember-meを使用すると、任意のURLをログインのエントリポイントにすることができます。ユーザーがブラウザを開いたときに最初にヒットするのがVarnishがスキップする(つまり、キャッシュをバイパスする)URLである場合、すべて問題ありませんが、ユーザーがホームページ(またはVarnishがキャッシュするもの)にアクセスすると、奇妙なことが起こります。ユーザーがログインすると、CookieTheftExceptionが発生し、remember-me Cookieがキャンセルされるため、それ以上の自動ログインはできなくなります。私がそれについて考えるとき、これらの2つ(覚えておいてください-私とワニス)は単に一緒に働くことは決してできないように思えます!これは本当ですか?

何がうまくいかなかったのか、何か考えはありますか?どうすれば覚えておくことができますか?私はワニスと一緒に仕事をしますか?ハッシュ関数が問題になる可能性はありますか?

以下にVarnish構成の一部を投稿しています(ハッシュ関数の定義をスキップしました。関連性があると思われる場合は、言ってください)。

sub vcl_recv {
    # Forward IP to Apache log
    unset req.http.X-Forwarded-For;
    set req.http.X-Forwarded-For = client.ip;

        if (req.http.host ~ "(?i)mysite\.com$") {
        if (req.restarts == 0) {
                    set req.backend = mysite;
        }
        else {
            error 750 "mysite";
        }
    }

    # static content should always be cached
    if (req.url ~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|pdf|mp3)$") {
        unset req.http.Cookie;
        return(lookup);
    }

    # only cache "get" or "head" requests
    if (req.request != "GET" && req.request != "HEAD") {
        return (pass);
    }

    # do not cache http authentication
    if (req.http.Authorization || req.http.Authenticate) {
        return (pass);
    }

    # do not cache Spring Security URLs, esi, personal pages etc.
        if (req.url ~ "^(/logout|/j_spring_security_check|/personal/)" || req.url ~ "\?service=esi") {
            return(pass);
    }

    return (lookup); # skip default vcl_recv
}

sub vcl_fetch { 
    # Try again if backend not responding
    if (beresp.status != 200 && beresp.status != 403 && beresp.status != 404 && beresp.status != 301 && beresp.status != 302 && beresp.status != 401) {
        return(restart);
    }

    # block sensitive files
    if (req.url ~ "\.(bak|conf|config|ear|exe|gz|jar|log|old|properties|tar|tmp|tgz|war)$") {
        error 405 "Not allowed";
    }

    # do esi processing for all non-static resources
    if (req.url !~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|xml|html|htm|pdf|mp3|doc)$") {       
        esi;
    }

    # do not cache when told not to
    if (req.http.Cache-Control ~ "no-cache") {
        return (pass);
    }

    # do not cache Spring Security URLs, esi, personal pages etc.
    if (req.url ~ "^(/logout|/j_spring_security_check|/personal/)" || req.url ~ "\?service=esi") {
        set beresp.http.Cache-Control = "private, no-cache, no-store, must-revalidate";
        set beresp.http.Pragma = "no-cache";
        set beresp.http.Expires = "Sat, 01 Jan 2000 00:00:00 GMT";
        return(pass);
    }

    # static content should always be cached
    if (req.url ~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|xml|html|htm|pdf|mp3|doc)$") {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1h;
    } else {
        set beresp.ttl = 300s;
    }
}

更新:ここで最終的な実装をうまく文書化しました。

4

1 に答える 1

2

RememberMe機能は、サーバーに特別なCookieを送信することで機能します。サーバーはCookieの値を解釈する方法を知っており(たとえば、ユーザー名とパスワードがそこにエンコードされているか、ユーザーにリンクする永続的なトークンが含まれています)、ユーザーのログインを実行できます。

デフォルト(default.vcl)では、VarnishはCookieを含むリクエストに干渉しません。Cookieは渡されます。ただし、vclファイルはリクエストCookieを参照せず、varnishに(vcl_recvで)ルックアップを実行するように指示します。すべてのクライアントはおそらく(SESSION)Cookieを持っているため、すべてではありませんが、多くの場合、要求Cookieを無視することは理にかなっています。

vclファイルはvcl_recv内のremembermeリクエストCookieを検出し、それに応じてパスを実行する必要があります。次のようなものです(ただし、Cookie名を確認してください):

if (req.http.Cookie ~ "rememberme=" ) {
   return (pass);
}

さらに、CookieTheftExceptionsが引き続き発生する場合は、set-cookieヘッダーを含む応答をキャッシュするかどうかを確認してください。このように、人々は同じセッションで終わります...

于 2011-09-12T15:38:32.140 に答える