原文:https://www.yuque.com/yuejiangliu/dotnet/gbzs4g


07 为 MVC 客户端刷新 Token.mp4 (72.6 MB)

本节是上节的补充,主要讲解如何使用 Refresh Token 刷新 Access Token。

设置并启用过期时间

打开 Idp 项目,修改 MVC Client 的 AccessTokenLifetime 为 60s:

// MVC client, authorization code
new Client
{
    ...
    // 设为 True 即支持 Refresh Token
    AllowOfflineAccess = true, // offline_access
    AccessTokenLifetime = 60, // 60 seconds

    AllowedScopes =
    {
        ...
    }
},

通过 jwt.io 能够看到过期时间设置在 Token 里面了。

07 为 MVC 客户端刷新 Token

结果发现 exp 都过了还能从 Api1 获得资源。

实际上是 Api1 中没有及时的验证 Token(默认为 300s 验证一次)。

修改 Api1,Token 验证间隔为 1 分钟,且 Token 必须包含过期时间:

services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;

        options.Audience = "api1";
        options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1);
        options.TokenValidationParameters.RequireExpirationTime = true;
    });

效果:过期后报错 Exception: Unauthorized

07 为 MVC 客户端刷新 Token

OpenID Connect 协议 构造 RefreshTokenRequest:

07 为 MVC 客户端刷新 Token

在 MVC Client 的 HomeController 中添加刷新 Token 的方法:

private async Task<string> RenewTokenAsync()
{
    var client = new HttpClient();
    var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000/");

    if (disco.IsError) throw new Exception(disco.Error);

    var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);

    // Refresh Access Token
    var tokenResponse = await client.RequestRefreshTokenAsync(new RefreshTokenRequest
    {
        Address = disco.TokenEndpoint,
        ClientId = "mvc client",
        ClientSecret = "mvc secret",
        Scope = "api1 openid profile email phone address",
        GrantType = OpenIdConnectGrantTypes.RefreshToken,
        RefreshToken = refreshToken
    });

    if (tokenResponse.IsError) throw new Exception(tokenResponse.Error);

    var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);

    var tokens = new[]
    {
        new AuthenticationToken
        {
            Name = OpenIdConnectParameterNames.IdToken,
            Value = tokenResponse.IdentityToken
        },
        new AuthenticationToken
        {
            Name = OpenIdConnectParameterNames.AccessToken,
            Value = tokenResponse.AccessToken
        },
        new AuthenticationToken
        {
            Name = OpenIdConnectParameterNames.RefreshToken,
            Value = tokenResponse.RefreshToken
        },
        new AuthenticationToken
        {
            Name = "expires_at",
            Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
        }
    };

    // 获取身份认证的结果,包含当前的 Principal 和 Properties
    var currentAuthenticateResult =
        await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    // 更新 Cookie 里面的 Token
    currentAuthenticateResult.Properties.StoreTokens(tokens);

    // 登录
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
        currentAuthenticateResult.Principal, currentAuthenticateResult.Properties);

    return tokenResponse.AccessToken;
}

相关文章:

  • 2021-05-20
  • 2021-10-11
  • 2021-11-25
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-04
猜你喜欢
  • 2021-08-09
  • 2022-12-23
  • 2021-11-23
  • 2022-12-23
  • 2022-02-22
  • 2022-01-03
  • 2021-05-09
相关资源
相似解决方案