Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.2.4-beta01</Version>
<Version>10.3.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
19 changes: 19 additions & 0 deletions src/BootstrapBlazor/Components/ConnectionHub/ConnectionHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
Expand Down Expand Up @@ -32,6 +35,11 @@ public class ConnectionHub : BootstrapModuleComponentBase
[NotNull]
private IOptions<BootstrapBlazorOptions>? BootstrapBlazorOptions { get; set; }

[Inject]
[NotNull]
Comment thread
ArgoZhang marked this conversation as resolved.
private IServiceProvider? Provider { get; set; }


Comment thread
ArgoZhang marked this conversation as resolved.
private IIpLocatorProvider? _ipLocatorProvider;

private ThrottleOptions? _throttleOptions;
Expand Down Expand Up @@ -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<AuthenticationStateProvider>();
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);
});
}
Expand Down
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/Services/WebClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,10 @@ public class ClientInfo
/// <para lang="en">Gets or sets Browser Engine Info</para>
/// </summary>
public string? Engine { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 当前已登录用户账号</para>
/// <para lang="en">Gets or sets currently logged-in user account</para>
/// </summary>
public string? UserName { get; set; }
}
29 changes: 29 additions & 0 deletions test/UnitTest/Services/ConnectionHubTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -17,6 +19,9 @@ public async Task Callback_Ok()
context.JSInterop.Mode = JSRuntimeMode.Loose;
context.Services.AddBootstrapBlazor();

var authorizationContext = new MockAuthenticationStateProvider();
context.Services.AddScoped<AuthenticationStateProvider>(p => authorizationContext);

var options = context.Services.GetRequiredService<IOptions<BootstrapBlazorOptions>>();
options.Value.ConnectionHubOptions = new()
{
Expand All @@ -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);
Expand All @@ -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();

Expand Down Expand Up @@ -155,4 +164,24 @@ public void ConnectionService_Ok()
var d = service as IDisposable;
d?.Dispose();
}

class MockAuthenticationStateProvider : AuthenticationStateProvider
Comment thread
ArgoZhang marked this conversation as resolved.
{
ClaimsPrincipal _claim = new();
public override async Task<AuthenticationState> 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"));
}
}
}