【问题标题】:IdentityServer4 Refresh Token: How to determine expiration time?IdentityServer4 Refresh Token:如何确定过期时间?
【发布时间】:2020-04-06 09:26:05
【问题描述】:

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

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

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

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

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

刷新令牌的最大生命周期(以秒为单位)。默认为 2592000 秒/30 天

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

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 秒,实际上是一个访问令牌的过期时间。我原以为是 2592000 秒。所以问题 #1 是:为什么会这样?

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

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

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

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

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

【问题讨论】:

  • 访问令牌过期,因为您正在请求访问令牌刷新令牌 仅充当密钥。如果您已将刷新令牌配置为仅使用一次,则还会返回一个新的刷新令牌,从而撤销当前的刷新令牌。我怀疑您可以通过以下方式读取到期时间:new JwtSecurityTokenHandler().ReadJwtToken(tokenResult.RefreshToken).ValidTo;
  • @RuardvanElburg - 感谢您的回复。不幸的是,我已经尝试使用JwtSecurityTokenHandler 来尝试计算TimeSpan。但是正如您所说,刷新“令牌”似乎不是完整的 JWT,因此 Read 方法失​​败。我会将其添加到主帖中。
  • 我正在尝试解决与您相同的情况。我们采取的策略是,如果出于任何原因,使用刷新令牌请求新的访问令牌失败,我们会要求我们的用户再次登录。在实践中,这对我们来说效果很好。会话 cookie 和访问令牌的到期时间都比刷新令牌短得多。因此,无论哪个先过期,最终都会请求一个新的刷新令牌。我们认为刷新令牌过期是一种例外情况。

标签: c# identityserver4 refresh-token


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    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
        });
    }
    

    【讨论】:

    • 在调用 GetRefreshTokenAsync() 时最好使用 async/await,而不是 .Result。
    猜你喜欢
    • 1970-01-01
    • 2018-11-06
    • 2019-02-18
    • 2020-05-12
    • 2021-12-29
    • 2012-05-27
    • 2018-12-22
    • 2018-11-19
    • 1970-01-01
    相关资源
    最近更新 更多