简体   繁体   中英

SignalR hub with Bearer authentication

I have a problem. I have in my API JWT Bearer authentication. I try to use SignalR hub with authentication but it doesn't work for me. I think I tried everything.

I have something like this:

.AddJwtBearer(conf =>
                {
                    conf.RequireHttpsMetadata = false;
                    conf.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(key),
                        ValidateIssuer = false,
                        ValidateAudience = false
                    };
                    conf.Events = new JwtBearerEvents
                    {
                        OnMessageReceived = context =>
                        {
                            // THIS DOESN'T WORK - empty string
                            //var accessToken = context.Request.Query["access_token"];
                            var accessToken2 = context.Request.Headers["Authorization"];
                            // If the request is for our hub...
                            var path = context.HttpContext.Request.Path;
                            if (!string.IsNullOrEmpty(accessToken2) &&       
                            (path.StartsWithSegments("/DebateHub")))
                            {
                                // Read the token out of the query string
                                context.Token = accessToken2;     
                            }
                           // return Task.CompletedTask;
                           return Task.FromResult<object>(null);
                        }
                    };
                });

Register hub:

 app.UseEndpoints(endpoints =>
        {
            endpoints.MapAreaControllerRoute(
                name: "AreaAdmin",
                areaName: "Admin",
                pattern: "api/admin/{controller}/{action}");

            endpoints.MapAreaControllerRoute(
                name: "AreaMobile",
                areaName: "Mobile",
                pattern: "api/mobile/{controller}/{action}");

            endpoints.MapControllers();
            endpoints.MapHub<DebateHub>("/DebateHub");
            endpoints.MapHub<OnlineCountHub>("/onlinecount");
        });

Hub code:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class DebateHub : Microsoft.AspNetCore.SignalR.Hub
{      
    public override Task OnConnectedAsync()
    {
        string name = Context.User.Identity.Name;      
       
        Groups.AddToGroupAsync(Context.ConnectionId, name);
       
        return base.OnConnectedAsync();
    }
}

Client example:

var uri = "https://localhost:44275/DebateHub";         
        
var connection = new HubConnectionBuilder()
                     .WithUrl(uri,options =>
                          {                   
                               options.AccessTokenProvider = () => Task.FromResult("some_token");
                          })
                     .Build(); 
connection.StartAsync().Wait();

It doesn't work. I still have unauthorized when I try to connect to my DebateHub. All other controllers work with my authentication ok.

What am I doing wrong?

I'm not sure but I think that you should use cookies to authorize to hub.

Look here

You must uncomment this part of your code;

//var accessToken = context.Request.Query["access_token"];

when hub connection request comes to the server it only sets the token in 'context.Request.Query', as microsoft docs states not in context.Request.Headers["Authorization"].

The query string is used on browsers when connecting with WebSockets and Server-Sent Events due to browser API limitations.

Confirm in chrome network tab request headers to see where it is being sent.

Alternatively you can use this middleware in startup configure method which dose same thing by taking the token from query and setting it where expected to be.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM