IdentityServer4 Refresh Token:如何确定过期时间?

IdentityServer4 Refresh Token: How to determine expiration time?

我正在使用 Identity Server 4 示例代码。特别是,对于我正在使用混合流程的示例 MVC 客户端的客户端:https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Clients/src/MvcHybrid

对于服务器,我将 Identity Server 与内存客户端一起使用(没有 Entity Framework,也没有 ASP.Net 身份):https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Quickstarts

客户端和服务器都有非常普通的开箱即用配置。

我试图了解刷新令牌如何过期以及本机应用程序如何主动确定过期时间(在它被 API 拒绝之前)。我的理解是刷新令牌的默认有效期很长:

http://docs.identityserver.io/en/latest/topics/refresh_tokens.html:

Maximum lifetime of a refresh token in seconds. Defaults to 2592000 seconds / 30 days

但是,当示例代码请求刷新令牌时,我没有得到预期的到期时间。这是示例代码:

var disco = await _discoveryCache.GetAsync();
if (disco.IsError) throw new Exception(disco.Error);

var rt = await HttpContext.GetTokenAsync("refresh_token");
var tokenClient = _httpClientFactory.CreateClient();

var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest
{
    Address = disco.TokenEndpoint,

    ClientId = "mvc.hybrid",
    ClientSecret = "secret",
    RefreshToken = rt
});

tokenResult.ExpiresIn是3600秒,其实就是一个access token的过期时间。我原以为是 2592000 秒。所以问题 #1 是:为什么会这样?

但更重要的是,我知道当我使用 SQL 服务器作为数据存储时,刷新令牌的有效期实际上是默认的 30 天。有一个 table PersistedGrants 包含刷新令牌,有效期显然是从发布之日起 30 天。所以问题 #2 是:应用程序如何以编程方式确定它收到的刷新令牌的到期日期?

我已经尝试解析 RefreshToken 本身,但它并不是真正完整的 JWT,因此会引发错误:

var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessTokenResponse.RefreshToken);
var diff = jwt.ValidTo - jwt.ValidFrom;

我还搜索了 IdentityServer4 unit / integration tests,但找不到内省刷新令牌的示例。

据推测,该信息要么需要位于初始令牌响应中的某个位置,要么需要在 Identity Server 中内置一个端点。但是我找不到这些东西。

好的,所以答案是 access_token 响应中没有指示 refresh_token 过期时间的数据。此外,没有可用于检查过期的端点。

OAuth 规范对此没有任何说明,因此我不想更改 access_token 响应。如果需要,我最终制作了自己的端点 returns 到期时间。这是我的控制器操作,如果有人需要起点:

private readonly IRefreshTokenStore _refreshTokenStore; // inject this into your controller

...

[Route("[controller]/GetRefreshTokenExpiration")]
[Authorize(...YOUR SCOPE...)]
public async Task<IActionResult> GetRefreshTokenExpiration(string refreshTokenKey)
{
    var refreshToken = await this._refreshTokenStore.GetRefreshTokenAsync(refreshTokenKey);
    if (refreshToken == null)
    {
        return NotFound(new { message = "Refresh token not found" });
    }
    return Ok(new {
        message = "Refresh token found",
        lifetime_seconds = refreshToken.Lifetime
    });
}

当一个调用../token 我们得到 access_token、expires_in、refresh_expires_in、refresh_token 和其他东西

解码 access_token 以获取 ValidTo 从 ValidTo 中减去 expires_in,然后将 refresh_expires_in 添加到 ValidTo,这应该会为您提供 refresh_token 的到期日期。