Authentication Blazor服务器信号集线器缺少用户声明

Authentication Blazor服务器信号集线器缺少用户声明,authentication,signalr,blazor,claims,Authentication,Signalr,Blazor,Claims,我已经花了一个多月的时间来解决这个问题,但毫无结果 目标是在Blazor服务器应用程序的Signalr hub中获取用户声明。我在Github上上传了一个非常简单的应用程序。客户端可以通过单击按钮调用中心上的方法,中心方法将返回一条带有User.Identity.Name的消息。但是,由于用户声明为空,我无法获取名称 以下是存储库: 在这里和其他地方,很多人都在问同样的问题。信息/建议/解决方案分散。事实证明,我(可能是我编程水平的任何人)不可能将这些片段组合起来并使它们工作 我怀疑,对于一个

我已经花了一个多月的时间来解决这个问题,但毫无结果

目标是在Blazor服务器应用程序的Signalr hub中获取用户声明。我在Github上上传了一个非常简单的应用程序。客户端可以通过单击按钮调用中心上的方法,中心方法将返回一条带有User.Identity.Name的消息。但是,由于用户声明为空,我无法获取名称

以下是存储库:

在这里和其他地方,很多人都在问同样的问题。信息/建议/解决方案分散。事实证明,我(可能是我编程水平的任何人)不可能将这些片段组合起来并使它们工作

我怀疑,对于一个优秀的程序员来说,在上面这个简单的应用程序中把这些片段组合起来不会花费太多时间。我相信很多人,包括我自己,都会从中受益。我希望一些好心的撒玛利亚人能伸出援手。在这种情况下,请提出拉取请求。我会将代码保存在那里供其他人使用,并在以后尝试添加手册。我还会回来尝试用一个类似简单的Blazor WASM应用程序做同样的事情

非常感谢本回购协议

受保护的重写异步任务OnInitializedAsync()
{
hubConnection=新的HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsolutionUri(“/chathub”),选项=>
{
options.AccessTokenProvider=async()=>
{
var accessTokenResult=等待AccessTokenProvider.RequestAccessToken();
accessTokenResult.TryGetToken(out var accessToken);
返回accessToken.Value;
};
})
.Build();
hubConnection.On(“接收消息”(用户,消息)=>
{
var encodedMsg=$“{user}:{message}”;
messages.Add(encodedMsg);
StateHasChanged();
});
等待hubConnection.StartAsync();
}
[授权]
公共类聊天室:聊天室
{
私有只读用户管理器用户管理器;
公共聊天中心(用户管理器用户管理器)
{
this.userManager=userManager;
}
公共异步任务SendMessage(字符串用户,字符串消息)
{
var userId=Context.UserIdentifier;
var applicationUser=await userManager.FindByIdAsync(userId);
等待Clients.All.SendAsync(“ReceiveMessage”,applicationUser.Email,message);
}
}

我想出了一个简单的解决方案,虽然不完美,但很好。我的目标是将一些用户信息传递给中心,这样我就可以用userid(或任何用户喜欢的信息)注册connectionid。到目前为止我还没有实现的可用解决方案建议在连接上添加一个令牌。相反,我将用户信息添加到标题中,并在集线器上提取它,如下所示:

这是客户端代码:

@code{
    [CascadingParameter]
    private Task<AuthenticationState> _authstate { get; set; }


    private HubConnection connection;
    private AuthenticationState authstate { get; set; }
    private List<string> messages = new List<string>();



    protected override async Task OnInitializedAsync()
    {
        authstate = await _authstate;

        if (authstate != null)
        {
            var userid = authstate.User.Identity.Name;

            connection = new HubConnectionBuilder()
                .WithUrl(NavigationManager.ToAbsoluteUri("/myhub"), options => {
                    options.Headers.Add("USERID", userid);
                })
                .WithAutomaticReconnect()
                .Build();



            connection.On<string, string>("ReceiveMessage", ReceiveMessage);

            await connection.StartAsync();
        }
    }


    public void ReceiveMessage(string user, string msg)
    {
        messages.Add(user + " " + msg);
        StateHasChanged();
    }

    public async void InvokeSomething()
    {
        await connection.InvokeAsync("InvokeSomething");
    }
}
它起作用了。在OnConnectedAsync中也可以使用相同的功能

希望这对某人有帮助。github repo中的更新代码

集线器上的Authorize属性正在使应用程序崩溃。因此,我认为与中心的连接没有经过身份验证(microsoft文档声称我们不需要做任何其他事情)。我希望比我有更好技能的人能提供更好的解决方案。与此同时,这似乎在起作用

更新 解决方案
为了启用集线器类的授权,必须将用户通过Blazor服务器SPA应用程序身份验证时创建的安全cookie传递给Blazor服务器SPA应用程序。创建集线器连接时,应该传递cookie。这将允许您通过上下文对象访问中心中的所有声明,例如UserIdentofier和UserName through。

@Chinez非常感谢您的编辑。我已经下载了你的代码,会处理的。您的解决方案似乎是针对WASM的,我无法使其在上面的Blazor服务器应用程序中工作。不过我会继续努力的。谢谢。@aadurham很抱歉我错过了。创建
hubconnection
的选项是关键。仍然非常有用,我也一直计划为wasm发布另一个问题,因为有这么多人在问这个问题。很高兴你也发布了回购协议,谢谢!谢谢,我想我已经解决了这个问题。虽然不完美,但很有效。我在下面解释。根本不需要处理令牌,只需在连接时将您喜欢的内容添加到头中即可。再次感谢,您的解决方案将在WASM中派上用场。
[Authorize]
public class ChatHub : Hub
{
    private readonly UserManager<ApplicationUser> userManager;

    public ChatHub(UserManager<ApplicationUser> userManager)
    {
        this.userManager = userManager;
    }

    public async Task SendMessage(string user, string message)
    {
        var userId = Context.UserIdentifier;
        var applicationUser = await userManager.FindByIdAsync(userId);

        await Clients.All.SendAsync("ReceiveMessage", applicationUser.Email, message);
    }
}

@code{
    [CascadingParameter]
    private Task<AuthenticationState> _authstate { get; set; }


    private HubConnection connection;
    private AuthenticationState authstate { get; set; }
    private List<string> messages = new List<string>();



    protected override async Task OnInitializedAsync()
    {
        authstate = await _authstate;

        if (authstate != null)
        {
            var userid = authstate.User.Identity.Name;

            connection = new HubConnectionBuilder()
                .WithUrl(NavigationManager.ToAbsoluteUri("/myhub"), options => {
                    options.Headers.Add("USERID", userid);
                })
                .WithAutomaticReconnect()
                .Build();



            connection.On<string, string>("ReceiveMessage", ReceiveMessage);

            await connection.StartAsync();
        }
    }


    public void ReceiveMessage(string user, string msg)
    {
        messages.Add(user + " " + msg);
        StateHasChanged();
    }

    public async void InvokeSomething()
    {
        await connection.InvokeAsync("InvokeSomething");
    }
}
public async Task InvokeSomething()
{
    var httpCtx = Context.GetHttpContext();
    var name = httpCtx.Request.Headers["USERID"].ToString();
    await Clients.All.SendAsync("ReceiveMessage", name, " invoked this");
}`