记住我的饼干和清漆

时间:2011-09-09 08:02:09

标签: spring-security varnish remember-me

我正在努力让Spring Security的记忆功能与Varnish一起使用,但这看起来非常难。通过常规登录,很容易,我只是设置Varnish绕过j_spring_security_check URL的缓存,但记住我,任何URL都可以作为登录的入口点。如果用户在打开浏览器时遇到的第一件事就是Varnish跳过的URL(即绕过缓存),那么一切都很好,但如果用户点击主页(或任何Varnish缓存的东西),就会发生一些奇怪的事情:用户确实登录,我得到一个CookieTheftException,因此记住我的cookie被取消,因此不可能进一步自动登录。 当我想到它时,听起来这两个(记住我和清漆)根本就不能一起工作!这可能是真的吗?

任何可能出错的想法?怎么可能记得我和Varnish一起工作?散列函数可能有问题吗?

我正在下面发布我的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;
    }
}

更新:我很好地记录了我的最终实施here

1 个答案:

答案 0 :(得分:2)

RememberMe功能通过向服务器发送特殊cookie来工作。服务器知道如何解释cookie值(例如,用户名+密码在那里编码,或者它包含链接到用户的持久令牌),并且可以为用户进行登录。

默认情况下(default.vcl),Varnish不会干扰包含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标头的任何响应。这样,人们最终会得到相同的会话......