|
11 | 11 | using Duende.AccessTokenManagement.OpenIdConnect; |
12 | 12 | using RichardSzalay.MockHttp; |
13 | 13 | using System.Net.Http.Json; |
| 14 | +using System.Security.Claims; |
| 15 | +using System.Text.Json; |
| 16 | +using Microsoft.Extensions.Options; |
| 17 | +using Duende.IdentityServer; |
| 18 | +using System.Threading; |
| 19 | +using Microsoft.Extensions.Logging; |
14 | 20 |
|
15 | 21 | namespace Duende.AccessTokenManagement.Tests; |
16 | 22 |
|
| 23 | +public class TokenRefresher( |
| 24 | + IStoreTokensInAuthenticationProperties tokensInProps, |
| 25 | + IOptions<UserTokenManagementOptions> options, |
| 26 | + IUserTokenRequestSynchronization sync, |
| 27 | + IUserTokenEndpointService tokenEndpointService, |
| 28 | + IUserTokenStore userAccessTokenStore, |
| 29 | + TimeProvider clock, |
| 30 | + ILogger<UserAccessAccessTokenManagementService> logger) |
| 31 | + |
| 32 | +{ |
| 33 | + public async Task ValidateToken(ClaimsPrincipal? user, AuthenticationProperties contextProperties, |
| 34 | + CancellationToken cancellationToken) |
| 35 | + { |
| 36 | + var userToken = tokensInProps.GetUserToken(contextProperties); |
| 37 | + var dtRefresh = userToken.Expiration.Subtract(options.Value.RefreshBeforeExpiration); |
| 38 | + var utcNow = clock.GetUtcNow(); |
| 39 | + |
| 40 | + var parameters = new UserTokenRequestParameters(); |
| 41 | + |
| 42 | + if (dtRefresh < utcNow) |
| 43 | + { |
| 44 | + //await sync.SynchronizeAsync(userToken.RefreshToken!, async () => |
| 45 | + //{ |
| 46 | + var refreshedToken = |
| 47 | + await tokenEndpointService.RefreshAccessTokenAsync(userToken, parameters, cancellationToken).ConfigureAwait(false); |
| 48 | + if (refreshedToken.IsError) |
| 49 | + { |
| 50 | + logger.LogError("Error refreshing access token. Error = {error}", refreshedToken.Error); |
| 51 | + } |
| 52 | + else |
| 53 | + { |
| 54 | + await userAccessTokenStore.StoreTokenAsync(user, refreshedToken, parameters).ConfigureAwait(false); |
| 55 | + } |
| 56 | + |
| 57 | + //return null; |
| 58 | + //}).ConfigureAwait(false); |
| 59 | + } |
| 60 | + |
| 61 | + } |
| 62 | + |
| 63 | +} |
| 64 | + |
17 | 65 | public class AppHost : GenericHost |
18 | 66 | { |
19 | 67 | public string ClientId; |
@@ -44,11 +92,20 @@ private void ConfigureServices(IServiceCollection services) |
44 | 92 | { |
45 | 93 | services.AddRouting(); |
46 | 94 | services.AddAuthorization(); |
| 95 | + services.AddTransient<TokenRefresher>(); |
47 | 96 |
|
48 | 97 | services.AddAuthentication("cookie") |
49 | 98 | .AddCookie("cookie", options => |
50 | 99 | { |
51 | 100 | options.Cookie.Name = "bff"; |
| 101 | + |
| 102 | + options.Events.OnValidatePrincipal += async context => |
| 103 | + { |
| 104 | + var refresher = context.HttpContext.RequestServices.GetRequiredService<TokenRefresher>(); |
| 105 | + |
| 106 | + await refresher.ValidateToken(context.Principal, context.Properties, context.HttpContext.RequestAborted); |
| 107 | + }; |
| 108 | + |
52 | 109 | }); |
53 | 110 |
|
54 | 111 | services.AddAuthentication(options => |
|
0 commit comments