I'm trying to add authentication to my signalR hub but it works only for the 'negotiate' method and not for every request sent to the hub.
In Startup.cs
under ConfigureService
I added :
// Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = GetTokenValidationParameters(authSettings.PublicKey);
options.IncludeErrorDetails = true;
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hubs")))
{
context.Token = accessToken;
}
return Task.CompletedTask;
},
};
});
In the Configure
method I added:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/hubs"), config => config.UseAuthentication());
And added the [Authorize]
attribute on the hub class:
[Authorize]
public class ProtocolMethodsHub : Hub<IProtocolMethodsHub>, IProtocolMethodsHub {}
I set a breakpoint in the OnMessageReceived
but it is called only when connecting to signalR and not for each request the is sent through the websocket .
Is there a way to authenticate/authorize each request to the hub?
CodePudding user response:
It feels wrong to per request add/remove middleware like this:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/hubs"), config => config.UseAuthentication());
You can better handle that in the authorization part of the system. AddJwtBearer does not care if the incoing request contains a token or not. Just that, if thr request contains a token, then it should be valid. AddJwtBearer does care about what you are allowed to do, that job is the authorization part. All AddJwtBearer wants to do is to create a User object based on the incoming token.
CodePudding user response:
SignalR uses different transports under the hood and each transport can behave a bit differently. For example, if it is using Websocket transport, you are creating a persistent connection between the server and the client and all of the requests go through this connection (which is different than normal HTTP requests) so it only checks the JWT validity during the establishment of the connection. For other transports, the checks happen more often but they still happen only when you are establishing the client connection to the server. In other words, you have already checked the JWT and you know it is valid when the requests start coming in, and SignalR does not double-check the JWT. If you would like to control the authorization and access by the JWT, you might want to either:
- Use different hubs with different levels of access.
- In your SignalR hub check the claims of the token to see if the user has access to what they are doing.