首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有SignalR (AuthenticationTypes.Federation)的OpenId集线器返回401

带有SignalR (AuthenticationTypes.Federation)的OpenId集线器返回401
EN

Stack Overflow用户
提问于 2021-09-11 18:57:47
回答 1查看 162关注 0票数 2

我有一个使用OpenId进行身份验证的应用程序。启动过程中的代码是:

代码语言:javascript
复制
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中,如下所示:

代码语言:javascript
复制
endpoints.MapHub<SpecialMessageHub>("myspecialhub");

除了发布我的整个Startup.cs文件之外,下面是一个简单的概述:

  1. app.UseAuthentication();app.UseAuthorization();app.UseEndpoints
  2. services.AddSignalR();services.AddServerSideBlazor();之前,services.AddAuthenticationservices.AddAuthorization

之后

我简化了这个问题的集线器:

代码语言:javascript
复制
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是我项目中的一种扩展方法

我有一个简单的组件来测试这个:

代码语言:javascript
复制
@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();
    }
}

然后将该组件添加到我的视图中,如下所示:

代码语言:javascript
复制
<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连接将自动继承此身份验证。

我能够验证用户是经过身份验证的,并且在控制器和组件中都有我正在寻找的声明。我觉得这应该是相当简单的,不需要多次跳,所以任何帮助都将是非常感谢的。

以下是我尝试过的一些事情:

  1. 从视图中的上下文中提取"access_token“和"id_token”,并将其作为参数传递给组件。然后,基于这里的https://learn.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1#bearer-token-authentication,我做了类似的事情,但这仍然导致401:

参数公共字符串AccessToken { get;set;}受保护的覆盖异步任务OnInitializedAsync() { if (!IsConnected) { hubConnection =新的HubConnectionBuilder() hubConnection options => { options.AccessTokenProvider = () => Task.FromResult(AccessToken);}) .WithAutomaticReconnect() .Build();hubConnection.On ("ReceiveMessage",(用户,消息) => { myMessage = message;StateHasChanged();});等待=> }

  1. I试图通过将ClaimsPrincipal替换为新的IIdentity,并将AuthenticationType设置为CookieAuthenticationDefaults.AuthenticationScheme来操纵用户。这导致了一个令人讨厌的无限循环,但是在重新启动应用程序之后,身份被交换了,但是,我仍然收到了401.

  1. 我也尝试过其他选择,但我似乎无法让它与OpenId.

一起工作。

EN

回答 1

Stack Overflow用户

发布于 2021-09-16 18:34:09

总之,Blazor组件正在服务器上运行,所以正在制作的HubConnection是从服务器到服务器的。

代码语言:javascript
复制
await hubConnection.StartAsync().ConfigureAwait(false);

这就建立了服务器到服务器的连接,这就是为什么HubCallerContext.User不是登录到web应用程序的用户。

就我个人而言,这是不直观的。因为这是在服务器上运行的,所以没有用浏览器建立的套接字。为了实现这一点,我们必须使用Blazor在客户端浏览器上运行代码。我又回到了用JavaScript来处理这件事。

下面是微软回答这一问题的原因:https://github.com/dotnet/aspnetcore/issues/36421

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69145892

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档