Here is my problem. I can't seem to manage to create an integration test that requires an authenticated user. I use Microsoft.AspNetCore.Mvc.Testing for testing. Here is my test:
As seen the client has the role "Patient" and a UserId. Here are my helpers:
public class TestClaimsProvider
{
public IList<Claim> Claims { get; }
public TestClaimsProvider(IList<Claim> claims)
{
Claims = claims;
}
public TestClaimsProvider()
{
Claims = new List<Claim>();
}
public static TestClaimsProvider WithAdminClaims()
{
var provider = new TestClaimsProvider();
provider.Claims.Add(new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()));
provider.Claims.Add(new Claim(ClaimTypes.Name, "Admin user"));
provider.Claims.Add(new Claim(ClaimTypes.Role, "Administrator"));
return provider;
}
public static TestClaimsProvider WithUserClaims()
{
var provider = new TestClaimsProvider();
provider.Claims.Add(new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()));
provider.Claims.Add(new Claim(ClaimTypes.Name, "Patient"));
provider.Claims.Add(new Claim(ClaimTypes.Role, "Patient"));
return provider;
}
}
This also:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IList<Claim> _claims;
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock, TestClaimsProvider claimsProvider) : base(options, logger, encoder, clock)
{
_claims = claimsProvider.Claims;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var identity = new ClaimsIdentity(_claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
And:
public static class WebApplicationFactoryExtensions
{
public static WebApplicationFactory<T> WithAuthentication<T>(this WebApplicationFactory<T> factory, TestClaimsProvider claimsProvider) where T : class
{
return factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", op => { });
services.AddScoped<TestClaimsProvider>(_ => claimsProvider);
});
});
}
public static HttpClient CreateClientWithTestAuth<T>(this WebApplicationFactory<T> factory, TestClaimsProvider claimsProvider) where T : class
{
var client = factory.WithAuthentication(claimsProvider).CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
return client;
}
These are based on this subject https://gunnarpeipman.com/aspnet-core-integration-tests-users-roles/. Although I am not using the FakeStartup class that he has pointed in previous threads. Also I have tried the authentication from the docs here https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0#customize-the-client-with-withwebhostbuilder but it is the same.
Here is my action method in the controller:
[Authorize(Roles = PatientRoleName)]
public async Task<IActionResult> MakePatientAppointment()
{
var patient = await this.patientService.GetPatientByUserIdAsync(this.User.GetId());
if (string.IsNullOrWhiteSpace(patient.FirstName) ||
string.IsNullOrWhiteSpace(patient.LastName) ||
string.IsNullOrWhiteSpace(patient.Phone))
{
this.TempData["Message"] = PatientProfileIsNotFinishedMsg;
return RedirectToAction("Finish", "Patient", new { area = "" });
}
var viewModel = new PatientAppointmentCreateModel
{
DoctorId = await this.doctorService.GetDoctorId(),
AppointmentCauses = await this.appointmentCauseService.GetAllCauses()
};
return View(viewModel);
}
From debugging the test the response redirect is to /Identity/Login, so from what I am understanding the user is not logged in. How can I refactor the code to manage to get the user authenticated?

