Skip to content

Commit 859aff4

Browse files
committed
Add BlazorAuthOptions & InitialAuthenticationState
1 parent 23d2ade commit 859aff4

10 files changed

Lines changed: 85 additions & 37 deletions

File tree

sample/BitzArt.Blazor.Auth.SampleApp/BitzArt.Blazor.Auth.SampleApp.Client/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BitzArt.Blazor.Auth.Client;
2+
using Microsoft.AspNetCore.Components.Authorization;
23
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
34

45
namespace BitzArt.Blazor.Auth.SampleApp.Client;

sample/BitzArt.Blazor.Auth.SampleApp/BitzArt.Blazor.Auth.SampleApp.Shared/Components/UserAuthenticationPane.razor

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
<AuthorizeView>
44

5+
<Authorizing>
6+
<div>
7+
<h4>
8+
Authorizing...
9+
</h4>
10+
</div>
11+
</Authorizing>
12+
513
<NotAuthorized>
614
<div>
715
<h4>

sample/BitzArt.Blazor.Auth.SampleApp/BitzArt.Blazor.Auth.SampleApp.Shared/Pages/InteractiveServerPage.razor

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,14 @@
66

77
<RendererInfoPane />
88

9-
<UserAuthenticationPane />
9+
<UserAuthenticationPane />
10+
11+
@code {
12+
[CascadingParameter]
13+
public Task<AuthenticationState> _authTask { get; set; }
14+
15+
protected override void OnParametersSet()
16+
{
17+
base.OnParametersSet();
18+
}
19+
}

sample/BitzArt.Blazor.Auth.SampleApp/BitzArt.Blazor.Auth.SampleApp/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using BitzArt.Blazor.Auth.SampleApp.Services;
22
using BitzArt.Blazor.Auth.Server;
3+
using Microsoft.AspNetCore.Components.Authorization;
34

45
namespace BitzArt.Blazor.Auth.SampleApp;
56

src/BitzArt.Blazor.Auth.Client/Extensions/ClientSideAddBlazorAuthExtension.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ public static class ClientSideAddBlazorAuthExtension
1414
/// Adds client-side Blazor.Auth services to the specified <see cref="WebAssemblyHostBuilder"/>.
1515
/// </summary>
1616
/// <param name="builder">The <see cref="WebAssemblyHostBuilder"/> to add services to.</param>
17+
/// <param name="configure">An <see cref="Action"/> to configure <see cref="BlazorAuthOptions"/>.</param>
1718
/// <returns><see cref="WebAssemblyHostBuilder"/> to allow chaining.</returns>
18-
public static WebAssemblyHostBuilder AddBlazorAuth(this WebAssemblyHostBuilder builder)
19+
public static WebAssemblyHostBuilder AddBlazorAuth(this WebAssemblyHostBuilder builder, Action<BlazorAuthOptions>? configure = null)
1920
{
21+
var options = new BlazorAuthOptions();
22+
configure?.Invoke(options);
23+
builder.Services.AddSingleton(options);
24+
2025
builder.AddBlazorCookies();
2126
builder.Services.AddScoped<IBlazorAuthLogger, BlazorAuthLogger>();
2227

src/BitzArt.Blazor.Auth.Server/Extensions/ServerSideAddBlazorAuthExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public static IHostApplicationBuilder AddBlazorAuth<TAuthenticationService, TIde
4747
configure?.Invoke(options);
4848
builder.Services.AddSingleton(options);
4949

50+
builder.Services.AddSingleton<BlazorAuthOptions>(sp => sp.GetRequiredService<BlazorAuthServerOptions>());
51+
5052
builder.AddBlazorCookies();
5153
builder.Services.AddScoped<IBlazorAuthLogger, BlazorAuthLogger>();
5254

src/BitzArt.Blazor.Auth.Server/Options/BlazorAuthServerOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// <summary>
44
/// Options for the Blazor Auth Server.
55
/// </summary>
6-
public class BlazorAuthServerOptions
6+
public class BlazorAuthServerOptions : BlazorAuthOptions
77
{
88
/// <summary>
99
/// Allows the app to operate in a non-HTTPS environment.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.AspNetCore.Components.Authorization;
2+
3+
namespace BitzArt.Blazor.Auth;
4+
5+
/// <summary>
6+
/// Options for configuring Blazor.Auth
7+
/// </summary>
8+
public class BlazorAuthOptions
9+
{
10+
/// <summary>
11+
/// Initial authentication state to use before the real state is resolved.
12+
/// </summary>
13+
public AuthenticationState? InitialAuthenticationState { get; set; }
14+
}

src/BitzArt.Blazor.Auth/Providers/BlazorAuthAuthenticationStateProvider.cs

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,61 @@
33
namespace BitzArt.Blazor.Auth;
44

55
/// <inheritdoc/>
6-
internal class BlazorAuthAuthenticationStateProvider : AuthenticationStateProvider
6+
internal class BlazorAuthAuthenticationStateProvider(IUserService userService, BlazorAuthOptions options) : AuthenticationStateProvider
77
{
8-
private readonly IUserService _userService;
98

10-
private readonly SemaphoreSlim _semaphore;
11-
private Task<AuthenticationState>? _authenticationStateTask;
9+
#if NET8_0
10+
private readonly static object _lock = new();
11+
#elif NET9_0_OR_GREATER
12+
private readonly static Lock _lock = new();
13+
#endif
1214

13-
public BlazorAuthAuthenticationStateProvider(IUserService userService)
14-
{
15-
_userService = userService;
16-
17-
_semaphore = new(1);
18-
}
15+
private Task<AuthenticationState>? _currentTask;
16+
private Task<AuthenticationState>? _initialResult = options.InitialAuthenticationState is not null
17+
? Task.FromResult(options.InitialAuthenticationState)
18+
: null;
1919

2020
/// <inheritdoc/>
21-
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
21+
public override Task<AuthenticationState> GetAuthenticationStateAsync()
2222
{
23-
bool isPrimary = false;
24-
Task<AuthenticationState>? task = null;
25-
26-
await _semaphore.WaitAsync();
27-
28-
try
23+
lock (_lock)
2924
{
30-
if (_authenticationStateTask is null)
25+
if (_currentTask is not null)
3126
{
32-
isPrimary = true;
33-
task = _userService.GetAuthenticationStateAsync();
34-
_authenticationStateTask = task;
27+
return _currentTask;
3528
}
36-
else
37-
{
38-
task = _authenticationStateTask;
39-
}
4029
}
41-
finally
30+
31+
var task = ResolveStateAsync();
32+
33+
if (_initialResult is not null)
4234
{
43-
_semaphore.Release();
35+
return _initialResult;
4436
}
4537

46-
if (isPrimary)
38+
return task;
39+
}
40+
41+
private Task<AuthenticationState> ResolveStateAsync()
42+
{
43+
try
4744
{
48-
NotifyAuthenticationStateChanged(_authenticationStateTask);
49-
var result = await task;
50-
_authenticationStateTask = null;
51-
return result;
45+
_currentTask = userService.GetAuthenticationStateAsync();
46+
return _currentTask;
5247
}
48+
finally
49+
{
50+
NotifyAuthenticationStateChanged(_currentTask!);
5351

54-
return await task!;
52+
if (_initialResult is not null)
53+
{
54+
_initialResult = _currentTask;
55+
}
56+
57+
lock (_lock)
58+
{
59+
_currentTask = null;
60+
}
61+
}
5562
}
5663
}

tests/BitzArt.Blazor.Auth.Tests/BlazorAuthAuthenticationStateProviderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public Task SignOutAsync(CancellationToken cancellationToken = default)
2828
public async Task GetAuthenticationStateAsync_Simaltaneous_ShouldReuseTheSameRequest()
2929
{
3030
// Arrange
31-
var provider = new BlazorAuthAuthenticationStateProvider(new TestUserService());
31+
var provider = new BlazorAuthAuthenticationStateProvider(new TestUserService(), new());
3232

3333
// Act
3434
var primaryTask = provider.GetAuthenticationStateAsync();

0 commit comments

Comments
 (0)