Skip to content

Commit 5d4d694

Browse files
committed
Improved changes regarding TimeProvider.
1 parent 92012d9 commit 5d4d694

File tree

9 files changed

+46
-17
lines changed

9 files changed

+46
-17
lines changed

Http/src/AppCoreNet.Extensions.Http.Authentication.OAuth.AspNetCore/AppCoreNet.Extensions.Http.Authentication.OAuth.AspNetCore.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
<FrameworkReference Include="Microsoft.AspNetCore.App" />
1414
</ItemGroup>
1515

16-
<ItemGroup>
17-
<PackageReference Include="Microsoft.Bcl.TimeProvider" Condition="'$(TargetFramework)'=='net6.0'" Version="8.0.1" />
18-
</ItemGroup>
19-
2016
<ItemGroup>
2117
<ProjectReference Include="..\AppCoreNet.Extensions.Http.Authentication.OAuth\AppCoreNet.Extensions.Http.Authentication.OAuth.csproj" />
2218
</ItemGroup>

Http/src/AppCoreNet.Extensions.Http.Authentication.OAuth.AspNetCore/OAuthUserTokenService.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using AppCoreNet.Diagnostics;
1212
using IdentityModel;
1313
using IdentityModel.Client;
14-
using Microsoft.AspNetCore.Authentication;
1514
using Microsoft.Extensions.Logging;
1615
using Microsoft.Extensions.Options;
1716

@@ -27,7 +26,6 @@ public abstract class OAuthUserTokenService<TOptions> : IOAuthUserTokenService
2726
private static readonly ConcurrentDictionary<string, Lazy<Task<OAuthUserToken>>> _sync = new ();
2827
private readonly IOAuthTokenClient _client;
2928
private readonly IOAuthUserTokenStore _store;
30-
private readonly TimeProvider _timeProvider;
3129
private readonly IOptionsMonitor<TOptions> _optionsMonitor;
3230
private readonly ILogger _logger;
3331

@@ -36,25 +34,21 @@ public abstract class OAuthUserTokenService<TOptions> : IOAuthUserTokenService
3634
/// </summary>
3735
/// <param name="client">The <see cref="IOAuthTokenClient"/>.</param>
3836
/// <param name="store">The <see cref="IOAuthUserTokenStore"/>.</param>
39-
/// <param name="timeProvider">The <see cref="TimeProvider"/>.</param>
4037
/// <param name="optionsMonitor">The <see cref="IOptionsMonitor{TOptions}"/>. </param>
4138
/// <param name="logger">The <see cref="ILogger"/>.</param>
4239
protected OAuthUserTokenService(
4340
IOAuthTokenClient client,
4441
IOAuthUserTokenStore store,
45-
TimeProvider timeProvider,
4642
IOptionsMonitor<TOptions> optionsMonitor,
4743
ILogger logger)
4844
{
4945
Ensure.Arg.NotNull(client);
5046
Ensure.Arg.NotNull(store);
51-
Ensure.Arg.NotNull(timeProvider);
5247
Ensure.Arg.NotNull(optionsMonitor);
5348
Ensure.Arg.NotNull(logger);
5449

5550
_client = client;
5651
_store = store;
57-
_timeProvider = timeProvider;
5852
_optionsMonitor = optionsMonitor;
5953
_logger = logger;
6054
}
@@ -94,10 +88,11 @@ public async Task<OAuthUserToken> GetAccessTokenAsync(
9488
EnsureCompatibleScheme(scheme);
9589

9690
TOptions options = _optionsMonitor.Get(scheme.Name);
91+
TimeProvider timeProvider = options.TimeProvider ?? TimeProvider.System;
9792
OAuthUserToken token = await _store.GetTokenAsync(scheme, user, cancellationToken);
9893

9994
DateTimeOffset? refreshAt = token.Expires?.Subtract(options.RefreshBeforeExpiration);
100-
if ((refreshAt.HasValue && refreshAt < _timeProvider.GetUtcNow())
95+
if ((refreshAt.HasValue && refreshAt < timeProvider.GetUtcNow())
10196
|| (parameters?.ForceRenewal).GetValueOrDefault())
10297
{
10398
if (!options.AllowTokenRefresh)
@@ -144,10 +139,13 @@ await _client.RequestRefreshTokenAsync(
144139
$"Error refreshing access token for client scheme '{scheme.Name}': {response.Error}");
145140
}
146141

142+
TOptions options = _optionsMonitor.Get(scheme.Name);
143+
TimeProvider timeProvider = options.TimeProvider ?? TimeProvider.System;
144+
147145
OAuthUserToken refreshedToken = new (
148146
response.AccessToken,
149147
response.RefreshToken,
150-
response.ExpiresIn > 0 ? _timeProvider.GetUtcNow() + TimeSpan.FromSeconds(response.ExpiresIn) : null);
148+
response.ExpiresIn > 0 ? timeProvider.GetUtcNow() + TimeSpan.FromSeconds(response.ExpiresIn) : null);
151149

152150
_logger.LogDebug(
153151
"Refreshed access token for client scheme {SchemeName}. Expiration: {Expiration}",

Http/src/AppCoreNet.Extensions.Http.Authentication.OAuth.OpenIdConnect/DependencyInjection/OpenIdConnectHttpClientAuthenticationBuilderExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public static IHttpClientAuthenticationBuilder AddOpenIdConnect(
7878

7979
services.TryAdd(new[]
8080
{
81-
ServiceDescriptor.Singleton(TimeProvider.System),
8281
ServiceDescriptor.Scoped<OpenIdConnectUserTokenService, OpenIdConnectUserTokenService>(),
8382
ServiceDescriptor.Scoped<OpenIdConnectUserTokenStore, OpenIdConnectUserTokenStore>(),
8483
});

Http/src/AppCoreNet.Extensions.Http.Authentication.OAuth.OpenIdConnect/OpenIdConnectUserTokenService.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed under the MIT license.
22
// Copyright (c) The AppCore .NET project.
33

4-
using System;
54
using AppCoreNet.Extensions.Http.Authentication.OAuth.AspNetCore;
65
using Microsoft.Extensions.Logging;
76
using Microsoft.Extensions.Options;
@@ -18,16 +17,14 @@ public class OpenIdConnectUserTokenService : OAuthUserTokenService<OpenIdConnect
1817
/// </summary>
1918
/// <param name="client">The <see cref="IOAuthTokenClient"/>.</param>
2019
/// <param name="store">The <see cref="OpenIdConnectUserTokenStore"/>.</param>
21-
/// <param name="timeProvider">The <see cref="TimeProvider"/>.</param>
2220
/// <param name="optionsMonitor">The <see cref="IOptionsMonitor{TOptions}"/>.</param>
2321
/// <param name="logger">The <see cref="ILogger"/>.</param>
2422
public OpenIdConnectUserTokenService(
2523
IOAuthTokenClient client,
2624
OpenIdConnectUserTokenStore store,
27-
TimeProvider timeProvider,
2825
IOptionsMonitor<OpenIdConnectUserOptions> optionsMonitor,
2926
ILogger<OpenIdConnectUserTokenService> logger)
30-
: base(client, store, timeProvider, optionsMonitor, logger)
27+
: base(client, store, optionsMonitor, logger)
3128
{
3229
}
3330

Http/src/AppCoreNet.Extensions.Http.Authentication/AppCoreNet.Extensions.Http.Authentication.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
</ItemGroup>
1515

1616
<ItemGroup Condition="'$(TargetFrameworks)' != 'net8.0'">
17+
<PackageReference Include="Microsoft.Bcl.TimeProvider" Version="8.0.1" />
1718
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
1819
</ItemGroup>
1920

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
// Licensed under the MIT license.
22
// Copyright (c) The AppCore .NET project.
33

4+
using System;
5+
46
namespace AppCoreNet.Extensions.Http.Authentication;
57

68
/// <summary>
79
/// Provides the base class for authentication scheme options.
810
/// </summary>
911
public abstract class AuthenticationSchemeOptions
1012
{
13+
/// <summary>
14+
/// Gets or sets the <see cref="System.TimeProvider"/> used for testing.
15+
/// </summary>
16+
public TimeProvider? TimeProvider { get; set; }
1117
}

Http/src/AppCoreNet.Extensions.Http.Authentication/DependencyInjection/HttpClientAuthenticationBuilderExtensions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using AppCoreNet.Extensions.Http.Authentication;
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Extensions.DependencyInjection.Extensions;
10+
using Microsoft.Extensions.Options;
1011

1112
// ReSharper disable once CheckNamespace
1213
namespace AppCoreNet.Extensions.DependencyInjection;
@@ -53,6 +54,14 @@ public static IHttpClientAuthenticationBuilder AddScheme<TOptions, TParameters,
5354
services.Configure(name, configure);
5455
}
5556

57+
services.TryAddEnumerable(
58+
new[]
59+
{
60+
ServiceDescriptor.Singleton<IPostConfigureOptions<TOptions>>(
61+
sp => new PostConfigureAuthenticationSchemeOptions<TOptions>(
62+
sp.GetRequiredService<TimeProvider>())),
63+
});
64+
5665
return builder;
5766
}
5867
}

Http/src/AppCoreNet.Extensions.Http.Authentication/DependencyInjection/HttpClientAuthenticationServiceCollectionExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed under the MIT license.
22
// Copyright (c) The AppCore .NET project.
33

4+
using System;
45
using AppCoreNet.Extensions.Http.Authentication;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -20,7 +21,9 @@ public static class HttpClientAuthenticationServiceCollectionExtensions
2021
/// <returns>The <see cref="IHttpClientAuthenticationBuilder"/> to configure the authentication.</returns>
2122
public static IHttpClientAuthenticationBuilder AddHttpClientAuthentication(this IServiceCollection services)
2223
{
24+
services.TryAddSingleton(TimeProvider.System);
2325
services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();
26+
2427
return new HttpClientAuthenticationBuilder(services);
2528
}
2629
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using Microsoft.Extensions.Options;
3+
4+
namespace AppCoreNet.Extensions.Http.Authentication;
5+
6+
internal sealed class PostConfigureAuthenticationSchemeOptions<TOptions> : IPostConfigureOptions<TOptions>
7+
where TOptions : AuthenticationSchemeOptions
8+
{
9+
private readonly TimeProvider _timeProvider;
10+
11+
public PostConfigureAuthenticationSchemeOptions(TimeProvider timeProvider)
12+
{
13+
_timeProvider = timeProvider;
14+
}
15+
16+
public void PostConfigure(string name, TOptions options)
17+
{
18+
options.TimeProvider ??= _timeProvider;
19+
}
20+
}

0 commit comments

Comments
 (0)