【问题标题】:Using JWT during SignalR connection with Blazor-WASM在 SignalR 与 Blazor-WASM 连接期间使用 JWT
【发布时间】:2020-10-04 01:49:54
【问题描述】:

我在搞乱 Blazor + SignalR 连接。我想使用 JWT 授权对 SignalR 的调用。

基本上我想附加到 SignalR 调用 JWT

这是我的 Blazor WASM SignalR 代码

@page "/"
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager NavigationManager
@implements IDisposable

<div class="form-group">
    <label>
        User:
        <input @bind="userInput" />
    </label>
</div>
<div class="form-group">
    <label>
        Message:
        <input @bind="messageInput" size="50" />
    </label>
</div>
<button @onclick="Send" disabled="@(!IsConnected)">Send</button>

<hr>

<ul id="messagesList">
    @foreach (var message in messages)
    {
        <li>@message</li>
    }
</ul>

@code {
    private HubConnection hubConnection;
    private List<string> messages = new List<string>();
    private string userInput;
    private string messageInput;

    protected override async Task OnInitializedAsync()
    {
        hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri("/chathub"))
            .Build();

        hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            var encodedMsg = $"{user}: {message}";
            messages.Add(encodedMsg);
            StateHasChanged();
        });

        await hubConnection.StartAsync();
    }

    Task Send() =>
        hubConnection.SendAsync("SendMessage", userInput, messageInput);

    public bool IsConnected =>
        hubConnection.State == HubConnectionState.Connected;

    public void Dispose()
    {
        _ = hubConnection.DisposeAsync();
    }
}

但我不确定如何将 JWT 附加到此

我在 Js 版的章节中看到过这个

Bearer token authentication

this.connection = new signalR.HubConnectionBuilder()
    .withUrl("/hubs/chat", { accessTokenFactory: () => this.loginToken })
    .build();

https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1#authenticate-users-connecting-to-a-signalr-hub

Blazor 的做法是什么?

我试过了:

var token = "eyJhb(...)";

hubConnection = new HubConnectionBuilder()
.WithUrl($"{Configuration["Url"]}/chathub", (HttpConnectionOptions x) =>
{
    x.Headers.Add("Authorization", $"Bearer: {token}");
})
.Build();

但它抛出了错误:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: The format of value 'Bearer: eyJh' is invalid.
System.FormatException: The format of value 'Bearer: eyJhbG' is invalid.

【问题讨论】:

  • @HenkHolterman 这很奇怪,因为我在Insomnia 中使用该令牌来ping 具有Authorize 属性的端点并且它工作正常,同时没有这个令牌我收到@987654329 @。我也在jwt.io 上试过,它说signature verified(OK)所以看起来令牌是OK

标签: jwt signalr blazor blazor-client-side


【解决方案1】:

解决方案是……阅读文档

var token = "eyJ";

hubConnection = new HubConnectionBuilder()
    .WithUrl($"{Configuration["Url"]}/chathub?access_token={token}")
    .Build();

在通过 url 建立连接时提供令牌

我们需要修改startup.cs来支持OnMessageReceived

文档网址:

https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1#authenticate-users-connecting-to-a-signalr-hub

services.AddAuthentication(options =>
{
    // Identity made Cookie authentication the default.
    // However, we want JWT Bearer Auth to be the default.
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    // Configure the Authority to the expected value for your authentication provider
    // This ensures the token is appropriately validated
    options.Authority = /* TODO: Insert Authority URL here */;

    // We have to hook the OnMessageReceived event in order to
    // allow the JWT authentication handler to read the access
    // token from the query string when a WebSocket or 
    // Server-Sent Events request comes in.

    // Sending the access token in the query string is required due to
    // a limitation in Browser APIs. We restrict it to only calls to the
    // SignalR hub in this code.
    // See https://docs.microsoft.com/aspnet/core/signalr/security#access-token-logging
    // for more information about security considerations when using
    // the query string to transmit the access token.
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];

            // If the request is for our hub...
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) &&
                (path.StartsWithSegments("/hubs/chat")))
            {
                // Read the token out of the query string
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        }
    };
});

【讨论】:

  • 您仍然应该在客户端上使用accessTokenFactory,这比在您的网址中放置查询字符串要干净得多。另外,它会尽可能使用标题而不是查询字符串。
  • @Brennan 你能给我举个例子吗?我找不到那个班级
  • 您在原始问题中确实使用了它.withUrl("/hubs/chat", { accessTokenFactory: () =&gt; this.loginToken })
  • @Brennan 这是 javascript 文档中的示例,但我在 C# 中找不到该类
猜你喜欢
  • 1970-01-01
  • 2021-05-09
  • 2020-08-23
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多