2011-05-10 85 views
6

Persistent Login Cookie Best Practice,你不应该允许“记住我”令牌竞争条件使用不止一次:持久性“记住我”饼干

永久Cookie是很好的一个单点登录。当确认身份验证时,用于登录的随机数无效,并分配一个全新的Cookie。标准会话管理处理会话生命期的凭证,因此新分配的cookie在下次会话之前不会被检查(在这一点上它也会在使用后失效)。

然后,如何处理用户在同一时间访问您网站上的多个URL的竞争情况?我实际上现在有这个问题。

假设两个请求同时从浏览器发送到服务器。这些请求不包含会话cookie,但包含相同的“记住我”cookie。其中一个请求将在另一个之前处理,并且将通过经过验证的会话cookie和重新生成的“记住我”cookie获得响应。

第二个请求中的“记住我”令牌现在已失效并且在服务器上生成另一个会话ID。此请求失败,因为用户无法通过身份验证。

我想出了一些可能的解决方案,但没有一个看起来很好。我错过了什么吗?

+0

我开始意识到问题是由于http是无状态的。如果“记住我”令牌没有立即失效,那么响应仍会返回不同的会话(并且浏览器会覆盖最后一个会话的旧会话)。 – 2011-05-10 13:22:48

回答

2

老问题,但我没有找到答案的任何地方。 我有同样的问题。我的解决方案是将旧标记存储在数据库上,并在未找到主标记时将其用作后备。但是我确定旧标记只在短时间内有效,就像标记更改后的几秒钟一样。然后,如果自上一次更新以来已经过去了一段时间,我只会更改该令牌,否则会出现令牌连续多次更改的情况。

1

为了详细说明vangoz的答案,我想补充一点,也必须采用某种锁定机制。这里考虑这个PHP上下的伪代码:

if (isFallback($token)) { 
    // Log the user in 
} else { 
    // Usual processing 
    // If token has to be updated, save old token as fallback for a few seconds 
} 

当有else分支,他们可能都结束了并发请求,一个请求会导致更新和其他将导致令牌无效。我解决这个问题的方法是使用一个命名锁,以$token的名字命名,来包装else分支。此外,所有并发的请求,但一个将无法获得锁,在这种情况下,我们睡一会儿并重试(重试时我们会发现令牌已成为后备令牌)。

if (isFallback($token)) { 
    // Log the user in 
} else { 
    $couldLock = lock($token); 
    if (!$couldLock) { 
    usleep(10000); 
    // Retry, possibly a recursive call 
    } else { 
    // Usual processing 
    // If token has to be updated, save old token as fallback for a few seconds 
    unlock($token); 
    } 
} 

我希望这些考虑可能有用。