我有一个reactjs网站和asp.net核心后端,并且刷新令牌有问题。
当某人登录我的网站时,他们会获得访问令牌和刷新令牌(相当标准)。现在,我设置了一个比访问令牌的时间短的计时器。
当他们打开多个标签时,所有这些都很好用。问题在于它们都共享本地存储(需要自动登录,因此不能使用会话存储)
场景
2个选项卡一个接一个地打开。访问令牌死亡前2分钟设置2个计时器。
第一次触发第一次将刷新令牌发送到服务器,并带回新的刷新/访问令牌。在服务器上,发送的刷新令牌将被删除。
第2个计时器在第一个计时器(第一个计时器正在工作时)后不久触发,但是现在很有可能已删除刷新令牌,从而使该请求无效。
如何停止这种比赛状态?
var foundRefreshToken = dbContext.Tokens.FirstOrDefault(x => x.Value == refreshToken);
if (foundRefreshToken == null)
{
return null;
}
var newRefreshToken = CreateRefreshToken(foundRefreshToken.ClientId, foundEmployee.Id);
dbContext.Tokens.Remove(foundRefreshToken);
dbContext.Tokens.Add(newRefreshToken);
dbContext.SaveChanges();
private Token CreateRefreshToken(string clientId, string userId)
{
return new Token()
{
ClientId = clientId,
EmployeeId = userId,
Value = GenerateRefreshToken(),
CreatedDate = DateTime.UtcNow
};
}
// high level js
refreshTimer;
setRefreshTimer(intervals) {
this.clearRefreshTimer();
this.refreshTimer = setInterval(() => {
this.refreshAuthentication();
}, intervals);
}
我能想到的仅有两件事是不要删除刷新令牌(但这会导致自动登录出现问题)
或者我在本地存储中有一个“锁定”第一个选项卡以进行刷新的标记,其他标记则等待查看是否执行该操作(猜测需要另一个计时器)。如果没有,那么下一个尝试。
还有其他想法吗?
答案 0 :(得分:0)
当您创建令牌和刷新令牌时,两者都应具有一个到期日期,例如:
return new Token()
{
ClientId = clientId,
EmployeeId = userId,
Value = GenerateRefreshToken(),
CreatedDate = DateTime.UtcNow,
ExpirationDate = <you decide>
};
在每个请求上,您都应该通过比较日期来检查令牌是否过期。如果已过期,则可以使用保持用户身份验证。最终,您甚至无法使刷新令牌过期,因为它必须由您的应用程序安全地存储。
刷新令牌和短期令牌背后的想法是,如果令牌被泄露,黑客只有10分钟的时间才需要刷新令牌来生成新令牌。
答案 1 :(得分:0)
最佳实践要求刷新令牌只能使用一次,并且每次使用新令牌时都应该使用。再次尝试使用旧的令牌应被视为是被盗的令牌-该用户的所有未完成的令牌应无效,任何新的访问尝试都需要完整登录。
当两个会话共享一个公共刷新令牌时(例如,在浏览器中打开两个选项卡并且该令牌存储在仅HTTP的cookie中时),就会发生竞争状态。当出现两个会话使用相同的刷新令牌同时尝试刷新的情况时,服务器的第一个会话将获得有效的新令牌,但是第二个会话发现它们的令牌现在无效并被注销。
如前所述,可以通过使用繁忙标志等机制在前端解决此问题,以便必须先完成第一次刷新,然后才能进行第二次刷新。
在后端,您可以使用一种机制,允许刷新令牌在完全失效或删除之前的很短时间内(仅几秒钟)重用。