diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index aa82b7cd133..10caab2a03a 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.2.4-beta01 + 10.3.0 diff --git a/src/BootstrapBlazor/Components/ConnectionHub/ConnectionHub.cs b/src/BootstrapBlazor/Components/ConnectionHub/ConnectionHub.cs index 94f33a949fb..b64071af55a 100644 --- a/src/BootstrapBlazor/Components/ConnectionHub/ConnectionHub.cs +++ b/src/BootstrapBlazor/Components/ConnectionHub/ConnectionHub.cs @@ -3,6 +3,9 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.Extensions.DependencyInjection; + namespace BootstrapBlazor.Components; /// @@ -32,6 +35,11 @@ public class ConnectionHub : BootstrapModuleComponentBase [NotNull] private IOptions? BootstrapBlazorOptions { get; set; } + [Inject] + [NotNull] + private IServiceProvider? Provider { get; set; } + + private IIpLocatorProvider? _ipLocatorProvider; private ThrottleOptions? _throttleOptions; @@ -77,6 +85,17 @@ await dispatch.ThrottleAsync(async () => _ipLocatorProvider ??= IpLocatorFactory.Create(BootstrapBlazorOptions.Value.IpLocatorOptions.ProviderName); client.City = await _ipLocatorProvider.Locate(client.Ip); } + + var authenticationStateProvider = Provider.GetService(); + if (authenticationStateProvider != null) + { + var state = await authenticationStateProvider.GetAuthenticationStateAsync(); + var identity = state.User.Identity; + if (identity is { IsAuthenticated: true }) + { + client.UserName = identity.Name; + } + } ConnectionService.AddOrUpdate(client); }); } diff --git a/src/BootstrapBlazor/Services/WebClientService.cs b/src/BootstrapBlazor/Services/WebClientService.cs index f9de69e357c..fa17f100159 100644 --- a/src/BootstrapBlazor/Services/WebClientService.cs +++ b/src/BootstrapBlazor/Services/WebClientService.cs @@ -180,4 +180,10 @@ public class ClientInfo /// Gets or sets Browser Engine Info /// public string? Engine { get; set; } + + /// + /// 获得/设置 当前已登录用户账号 + /// Gets or sets currently logged-in user account + /// + public string? UserName { get; set; } } diff --git a/test/UnitTest/Services/ConnectionHubTest.cs b/test/UnitTest/Services/ConnectionHubTest.cs index f33ec35590c..95fb2e273e4 100644 --- a/test/UnitTest/Services/ConnectionHubTest.cs +++ b/test/UnitTest/Services/ConnectionHubTest.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.Options; using Microsoft.JSInterop; +using System.Security.Claims; namespace UnitTest.Services; @@ -17,6 +19,9 @@ public async Task Callback_Ok() context.JSInterop.Mode = JSRuntimeMode.Loose; context.Services.AddBootstrapBlazor(); + var authorizationContext = new MockAuthenticationStateProvider(); + context.Services.AddScoped(p => authorizationContext); + var options = context.Services.GetRequiredService>(); options.Value.ConnectionHubOptions = new() { @@ -36,6 +41,7 @@ await cut.InvokeAsync(async () => await Task.Delay(100); client.SetData(new ClientInfo() { Id = "test_id", Ip = "::1" }); }); + await cut.Instance.Callback(new ClientInfo { Id = "test_id", Ip = "::1" }); }); Assert.Equal(1, service.Count); @@ -49,12 +55,15 @@ await cut.InvokeAsync(async () => // 触发 Beat 时间 await Task.Delay(200); + authorizationContext.SetAuthorized("mock_user"); await cut.InvokeAsync(async () => { await cut.Instance.Callback(new ClientInfo { Id = "test_id", Ip = "::1" }); }); Assert.True(service.TryGetValue("test_id", out var item)); Assert.NotNull(item?.ClientInfo); + Assert.Equal("mock_user", item.ClientInfo.UserName); + Assert.True(item?.ConnectionTime < DateTimeOffset.Now); cut.Dispose(); @@ -155,4 +164,24 @@ public void ConnectionService_Ok() var d = service as IDisposable; d?.Dispose(); } + + class MockAuthenticationStateProvider : AuthenticationStateProvider + { + ClaimsPrincipal _claim = new(); + public override async Task GetAuthenticationStateAsync() + { + await Task.Yield(); + + var state = new AuthenticationState(_claim); + return state; + } + + public void SetAuthorized(string userName) + { + _claim = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] + { + new(ClaimTypes.Name, userName), + }, "mock")); + } + } }