将JWT令牌作为QueryString传递到SignalR集线器

时间:2018-07-12 20:21:04

标签: signalr signalr-hub asp.net-core-signalr

尝试遵循以下链接中的建议,将JWT令牌传递到我的SignalR集线器,但到目前为止,它不起作用。特别是,请参阅David Fowler在2017年7月22日的建议。https://github.com/aspnet/SignalR/issues/130

我的前端是React,所以我只是将令牌添加到查询字符串中,如下所示,其中_token具有我的JWT令牌值:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/myhub?AUTHORIZATION=" + _token)
    .configureLogging(signalR.LogLevel.Information)
    .build();

在我的ConfigureServices()的{​​{1}}方法中,我对Startup.cs令牌进行了以下配置:

Jwt

这就是我的services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(jwtOptions => { jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/"; jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"]; jwtOptions.Events = new JwtBearerEvents { OnMessageReceived = context => { if(context.HttpContext.WebSockets.IsWebSocketRequest) context.Token = context.Request.Query["AUTHORIZATION"]; return Task.CompletedTask; } }; }); 的样子:

Hub

基本上,我遇到了[Authorize] public class MyHub : Hub { private IBackendService _backendService; public MyHub(IBackendService backendService) { _backendService = backendService; } public async Task SendMessage(string message) { // Regular SignalR stuff // SignalR will now send the message to all connected users... } } 错误。

我在检查该请求是否是Web套接字请求的地方放了一个断点,但没有找到它。似乎管道中的某些内容确定用户未通过身份验证。

我的代码在做什么错了?

2 个答案:

答案 0 :(得分:2)

您可以通过使用自定义中间件来解决从查询字符串中获取身份验证令牌的问题。

public class SignalRQueryStringAuthMiddleware
{
    private readonly RequestDelegate _next;

    public SignalRQueryStringAuthMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Convert incomming qs auth token to a Authorization header so the rest of the chain
    // can authorize the request correctly
    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers["Connection"] == "Upgrade" &&
            context.Request.Query.TryGetValue("authToken", out var token))
        {
            context.Request.Headers.Add("Authorization", "Bearer " + token.First());
        }
         await _next.Invoke(context);
    }
}

public static class SignalRQueryStringAuthExtensions
{
    public static IApplicationBuilder UseSignalRQueryStringAuth(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<SignalRQueryStringAuthMiddleware>();
    }
}

这将尝试获取查询字符串值“ authToken”,并将设置标头,以便您可以利用身份验证中间件。您需要在管道中的身份验证中间件之前调用它,如下所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //...

    app.UseSignalRQueryStringAuth();
    app.UseAuthentication();

    //...
}

编辑

在旁注中,仅应在用户登录后附加令牌:

if (accessToken) {
    hubUrl += '?authToken' +'=' + accessToken;
}

this._hubConnection = new HubConnectionBuilder()
                                .withUrl(hubUrl)
                                .build();

答案 1 :(得分:0)

我也在项目中实现了这一点。最简单的方法是在您的Configure方法中添加一个中间件。

    ExecutorLostFailure (executor 1 exited caused by one of the running tasks) Reason: Container from a bad node: container_1591270643256_0002_01_000002 on host: ip-172-31-35-232.eu-west-1.compute.internal. Exit status: 137. Diagnostics: Container killed on request. Exit code is 137

它的作用与其他答案中提到的相同。通过从查询字符串中读取令牌,将令牌添加到标头中。当然,您可以在一个单独的文件中分离出自定义中间件的实现。