Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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"));
}
}
}