【问题标题】:Passing JWT Token as QueryString to SignalR Hub将 JWT 令牌作为 QueryString 传递给 SignalR Hub
【发布时间】:2020-06-04 19:58:39
【问题描述】:

尝试按照以下链接中的建议将 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();

在我的Startup.csConfigureServices() 方法中,我对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...
   }
}

基本上,我收到了401 Unauthorized 错误。

我设置了一个断点来检查请求是否是网络套接字请求,但我没有点击它。看起来管道中的某些东西正在确定用户未通过身份验证。

我在代码中做错了什么?

【问题讨论】:

  • 看起来我们正在做一些类似的事情。如果您有任何其他问题,请在此处联系我。我很乐意提供帮助
  • @johnny5 非常感谢。对此,我真的非常感激。我还没有检查整个代码,但接受了你的解决方案作为答案,所以如果我有一些问题困扰你,请不要生我的气。
  • 别担心,你可以随时打扰我,我会随时为您提供帮助,我最近刚刚经历了这些困难。

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


【解决方案1】:

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

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();

【讨论】:

  • 等一下,我也需要从客户那里发布一个 sn-p
  • 这一切都很清楚,除了一个区域:看起来像在中间件中,你正在寻找Headers["Connection"] == "Upgrade"。这是否意味着您在 SignalR 连接中设置了一个名为 Connection 的自定义标头,其值为 Upgrade?如果是这样,你在哪里添加它?显然,我们试图将我们在中间件中所做的工作仅限于 SignalR 连接。您是否发现添加此标头是最好的方法?我见过有人在context.Request 或大卫福勒的例子中检查路径,他正在做context.HttpContext.WebSockets.IsWebSocketRequest
  • 我认为这是一个将其限制为信号器的检查,但请检查我是否可以找到关于该文件的文档
  • 如果你在Startup.csConfigure()方法中添加app.UseWebSockets();,我们可以使用context.Websockets.IsWebSocketRequest来检查请求是否是SignalR的传入请求——假设你没有'不要以任何其他方式使用WebSockets。诀窍是在app.UseAuthentication()app.UseSignalR() 之前使用它。
  • 我也这么认为。这是我发布的 GitHub 问题的链接。当我从创建该技术的团队那里得到答案时,我总是感觉更好:github.com/aspnet/SignalR/issues/130#issuecomment-404721480
【解决方案2】:

我也在我的项目中实现了这一点。执行此操作的最短方法是在您的 Configure 方法中添加一个中间件。

        app.Use(async (context, next) =>
        {
            var accessToken = context.Request.Query["access_token"];
            if (!string.IsNullOrEmpty(accessToken))
            {
                context.Request.Headers["authorization"] = "Bearer " + accessToken;
            }

            await next.Invoke().ConfigureAwait(false);
        });

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

【讨论】:

    猜你喜欢
    • 2019-09-21
    • 1970-01-01
    • 2023-01-30
    • 2019-04-10
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    • 2018-03-01
    相关资源
    最近更新 更多