代码之家  ›  专栏  ›  技术社区  ›  Sam

将JWT令牌作为查询字符串传递到信号器集线器

  •  2
  • Sam  · 技术社区  · 6 年前

    尝试按照下面链接中的建议通过 JWT 给我的信号器集线器的令牌,但到目前为止还没用。具体见大卫·福勒2017年7月22日的建议。 https://github.com/aspnet/SignalR/issues/130

    我的前端是 React 所以我只是将令牌添加到querystring中,如下所示 _token 有我的 智威汤逊 标记值:

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

    ConfigureServices() 我的方法 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...
       }
    }
    

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

    我设置了一个断点,检查请求是否是web sockets请求,但没有命中它。似乎管道中的某些内容正在确定用户未通过身份验证。

    我的代码哪里做错了?

    1 回复  |  直到 6 年前
        1
  •  2
  •   johnny 5    6 年前

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

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