How to use Authentication(JWT) on a signal R Hub on a .Net 6

64 Views Asked by At

I'm using signal R to send messages to other Users, I have a Hub called ChatHub but I just want to call the methods with the [Authorize] decorator, this is my hub:

public class ChatHub : Hub
{
[Authorize]
public async Task<Result> SendMessage(string nameSender, string userEmailSender, string 
emailReceiver, string receiverConnectionId, string message)
{
    var usuarioEmail = Context.UserIdentifier; // IS ALWAYS NULL
    if (usuarioEmail != null)
    {
        // DO SOMETHING
    }
}
}

This is my program class with the JWT configuration:

builder.Services
.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    // Configure the Authority to the expected value for
    // the authentication provider. This ensures the token
    // is appropriately validated.
    //options.Authority = "Authority URL";
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];

            // If the request is for our hub...
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) &&
                (path.StartsWithSegments("/hubs/chat")))
            {
                // Read the token out of the query string
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        }
    };
});

builder.Services.TryAddEnumerable(
        ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>,
        ConfigureJwtBearerOptions>());
builder.Services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();

this is other piece of code in my program class:

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Api V1");
});

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Api V1");
    });
}
app.UseCors(builder =>
{
    builder
        .AllowAnyHeader()
        .AllowAnyMethod()
        .AllowCredentials()
.WithOrigins("https://localhost:4200","http://localhost:4200");
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapHub<ChatHub>("/chatHub");
app.MapControllers();
app.Run();

Finally this is how I create my JWT in my controller:

private AuthenticationResponseModel BuildToken(UserCredentialsModel userCredentials, string userName)
{
    var claims = new List<Claim>()
    {
        new Claim("email", userCredentials.Email),
        new Claim("userName", userName),
        new Claim("connectionId", userCredentials.ConnectionId)
    };
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["jwtKey"]));
    var creds = new SigningCredentials(key, 
SecurityAlgorithms.HmacSha256);
    var expirationTime = DateTime.UtcNow.AddYears(1);

        

    var securityToken = new JwtSecurityToken(issuer: null, audience: null, claims: claims,
        expires: expirationTime, signingCredentials: creds);

// build token JWT
    var jwtToken = new 
JwtSecurityTokenHandler().WriteToken(securityToken);

// set up UserIdentifier in signal Rc context
    var userPrincipal = new ClaimsPrincipal(new 
ClaimsIdentity(claims, "jwt"));
    var userEmail = userPrincipal.FindFirst("email")?.Value;

    return new AuthenticationResponseModel()
    {
        Token = jwtToken,
        Expiration = expirationTime,
        UserName = userName,
        EmailUser = userCredentials.Email
    };
}

also I have an angular app for testing, I can call the method but the property: Context.UserIdentifier is always null, in my token I have 3 claims: email, userName, connectionId, how can I send the token and get from the Context.UserIdentifier the email or the userName ? I'm using .Net 6, Signal R

0

There are 0 best solutions below