我有一个使用OpenId进行身份验证的应用程序。启动过程中的代码是:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = new PathString("/account/login");
})
.AddOpenIdConnect("CustomScheme", options =>
{
// options configured
});我有一个集线器,并将集线器连接到app.UseEndpoints中,如下所示:
endpoints.MapHub<SpecialMessageHub>("myspecialhub");除了发布我的整个Startup.cs文件之外,下面是一个简单的概述:
app.UseAuthentication();和app.UseAuthorization();在app.UseEndpointsservices.AddSignalR();和services.AddServerSideBlazor();之前,services.AddAuthentication和services.AddAuthorization之后
我简化了这个问题的集线器:
using Example.Extensions;
using Example.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Threading;
using System.Threading.Tasks;
namespace Example.Hubs
{
[Authorize]
public class SpecialMessageHub : Hub
{
public override Task OnConnectedAsync()
{
var customerId = Context.User.GetCustomerId();
Groups.AddToGroupAsync(Context.ConnectionId, GetCustomerGroupName(customerId));
return base.OnConnectedAsync();
}
public Task SendMessage(string customerId,
SpecialMessage message,
CancellationToken cancellationToken)
{
return Clients.Groups(GetCustomerGroupName(customerId)).SendAsync("ReceiveMessage", message, cancellationToken);
}
public static string GetCustomerGroupName(string customerId) => $"customers-{customerId}";
}
}**注:GetCustomerId是我项目中的一种扩展方法
我有一个简单的组件来测试这个:
@page "/"
@using Microsoft.AspNetCore.SignalR.Client
@using Example.Models
@inject Microsoft.AspNetCore.Components.NavigationManager NavigationManager
@implements IAsyncDisposable
<h2>@myMessage.Id</h2>
<div>@myMessage.Message</div>
@code {
private HubConnection hubConnection;
private SpecialMessage myMessage = new SpecialMessage();
protected override async Task OnInitializedAsync()
{
if (!IsConnected)
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/myspecialhub"))
.WithAutomaticReconnect()
.Build();
hubConnection.On<string, SpecialMessage>
("ReceiveMessage", (user, message) =>
{
myMessage = message;
StateHasChanged();
});
await hubConnection.StartAsync().ConfigureAwait(false);
}
}
public bool IsConnected => hubConnection != null
&& hubConnection.State == HubConnectionState.Connected;
public async ValueTask DisposeAsync()
{
await hubConnection?.DisposeAsync();
}
}然后将该组件添加到我的视图中,如下所示:
<component type="typeof(SpecialMessageComponent)" render-mode="ServerPrerendered"/>当我点击这个视图时,它返回一个401:

基于这个https://learn.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1,应该将cookie传递给集线器:
在基于浏览器的应用程序
中,cookie身份验证允许您现有的用户凭据自动流到SignalR连接。当使用浏览器客户端时,不需要额外的配置。如果用户登录到您的应用程序,SignalR连接将自动继承此身份验证。
我能够验证用户是经过身份验证的,并且在控制器和组件中都有我正在寻找的声明。我觉得这应该是相当简单的,不需要多次跳,所以任何帮助都将是非常感谢的。
以下是我尝试过的一些事情:
参数公共字符串AccessToken { get;set;}受保护的覆盖异步任务OnInitializedAsync() { if (!IsConnected) { hubConnection =新的HubConnectionBuilder() hubConnection options => { options.AccessTokenProvider = () => Task.FromResult(AccessToken);}) .WithAutomaticReconnect() .Build();hubConnection.On ("ReceiveMessage",(用户,消息) => { myMessage = message;StateHasChanged();});等待=> }
ClaimsPrincipal替换为新的IIdentity,并将AuthenticationType设置为CookieAuthenticationDefaults.AuthenticationScheme来操纵用户。这导致了一个令人讨厌的无限循环,但是在重新启动应用程序之后,身份被交换了,但是,我仍然收到了401.。
一起工作。
发布于 2021-09-16 18:34:09
总之,Blazor组件正在服务器上运行,所以正在制作的HubConnection是从服务器到服务器的。
await hubConnection.StartAsync().ConfigureAwait(false);这就建立了服务器到服务器的连接,这就是为什么HubCallerContext.User不是登录到web应用程序的用户。
就我个人而言,这是不直观的。因为这是在服务器上运行的,所以没有用浏览器建立的套接字。为了实现这一点,我们必须使用Blazor在客户端浏览器上运行代码。我又回到了用JavaScript来处理这件事。
下面是微软回答这一问题的原因:https://github.com/dotnet/aspnetcore/issues/36421
https://stackoverflow.com/questions/69145892
复制相似问题