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