【发布时间】:2021-07-18 03:15:36
【问题描述】:
对于我的场景,我使用 ASP.NET Core 5 和 AzureAD(或 IdentityServer4 进行测试),但这可能会改变,因此请寻找任何一般和具体的指导。
注意:我在 Will an old refresh token still be valid if a new refresh token get issued? 看到了答案,但不清楚这是标准行为,还是 Google 特定的行为(问题所在)。
当可能发生并发请求时,处理刷新令牌的正确模式是什么?
在我的代码中,我正在捕获经过身份验证的刷新令牌和到期时间,即
options.Events = new OpenIdConnectEvents
{
// This is called during sign-in after the access token and refresh token are received
OnTokenResponseReceived = context =>
{
// Extract just the refresh token and put it in the cookie. (Note: This is ~64 bytes on IdentityServer4, but over 1KB in AzureAD)
string token = context.TokenEndpointResponse.RefreshToken;
string expires = context.TokenEndpointResponse.ExpiresIn; // e.g. "3600"
//...save the values in the ticket/cookie...
稍后在 OnValidatePrincipal 中,我正在检查令牌是否已过期,如果是,则尝试更新它,例如
var pairs = new Dictionary<string, string>() {
{ "client_id", oidcOptions.ClientId },
{ "client_secret", oidcOptions.ClientSecret },
{ "grant_type", "refresh_token" },
{ "refresh_token", refresh_token }
};
var result = await httpClient.PostAsync(oidcOptions.Authority + "/oauth2/token", new FormUrlEncodedContent(pairs));
// ... If successful, update the ticket with the new values..
现在假设令牌已过期,而浏览器恰好同时发送了 5 个新的 HTTP 请求(例如,在页面上加载了一堆图像)。如果服务器尝试同时处理所有这些请求,它将尝试同时兑换相同的 refresh_token。
https://docs.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview#token-types 的页面指出:
保存新的刷新令牌。它替换了您之前在请求中使用的刷新令牌。
那么旧的刷新令牌一旦使用就不再有效了吗?这意味着第一个请求成功并且旧的刷新令牌无效,并且所有其他正在进行的请求都将失败(因为刷新令牌将无法赎回已被使用的)。
如果是这种情况,我想使用刷新令牌的正确逻辑可能会非常复杂。 (如果没有,该机构是否应该维护一个有效刷新令牌的列表,或者允许“当前”和“新”令牌在一段时间内的有效性重叠?)
=== 更新 ===
作为额外信息,我只是对这两个提供程序进行了测试,但只是添加了额外的几行代码以进行两次相同的调用以刷新令牌(通过单步执行调试器会稍有延迟)。
var result = await httpClient.PostAsync(oidcOptions.Authority + oidcOptions.TokenEndpoint, new FormUrlEncodedContent(pairs));
if (runtwice)
{
var result2 = await httpClient.PostAsync(oidcOptions.Authority + oidcOptions.TokenEndpoint, new FormUrlEncodedContent(pairs));
var response1_body = await result.Content.ReadAsStringAsync();
var response2_body = await result2.Content.ReadAsStringAsync();
Trace.WriteLine(response1_body);
Trace.WriteLine(response2_body);
}
使用 AzureAD,它确实可以正常工作,并给了我两个单独的令牌,用于具有相同刷新令牌的调用:
// First call
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1619227041",
"access_token": "PAQABA...XeZLgIAA",
"refresh_token": "0.ATU...Bw_yB09Be8"
}
// Second call
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1619227046",
"access_token": "PAQABA...fLyZQIAA",
"refresh_token": "0.ATU...K8y7zOm1CQ"
}
使用 IdentityServer4,它拒绝了使用相同刷新令牌发出的第二个请求
// First call
{
"id_token":"eyJhbG...",
"access_token":"eyJhbGciOi...",
"expires_in":3600,
"token_type":"Bearer",
"refresh_token":"6D141...",
"scope":"openid profile email offline_access"
}
// Second call
{"error":"invalid_grant"}
我仍然不确定哪个是预期的行为,或者它是否是实现定义的(或可配置的)。
(注意:对于 IdentityServer4 似乎是可配置的:http://docs.identityserver.io/en/latest/topics/refresh_tokens.html#customizing-refresh-token-behavior)
【问题讨论】:
标签: oauth azure-active-directory identityserver4 refresh-token