Mocking an Authenticated User in Blazor/ASP.NET Core
I've done a couple of recent columns about securing Blazor Components and using claims-based policies declaratively in ASP.NET Core generally. While working with security, I'm always interested in doing end-to-end testing: Starting up the application and seeing what happens when I try to navigate to a page.
However, while that matters to me, I'm less interested in setting up users with a variety of different security configurations (so many names! so many passwords!). Inevitably while thinking I'm testing one authorization scenario, I pick a user that actually represents a different scenario.
So I created a MockAuthenticatedUser class that, once added to my application's middleware, creates an authenticated user for my application. I find it easier to configure my mock user's authorization claims in code before running a test than it is to maintain (and remember) a variety of users.
If you think you might find it useful, you can add it to your processing pipeline with code like this in your Startup class' ConfigureServices method:
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions,
MockAuthenticatedUser>("BasicAuthentication", null);
To use this class, you'll also need this line in your Startup class' Configure method:
app.UseAuthentication();
I should be clear that I've only used this to test Controllers so it might behave differently with Razor Pages.
Here's the code for my MockAuthenticatedUser class that configures a user with a name, an Id, a role, and some random claims:
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace SampleBlazor.Models
{
public class MockAuthenticatedUser : AuthenticationHandler<AuthenticationSchemeOptions>
{
const string userId = "phv";
const string userName = "Jean Irvine";
const string userRole = "ProductManager";
public MockAuthenticatedUser(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock){ }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, userId),
new Claim(ClaimTypes.Name, userName),
new Claim(ClaimTypes.Role, userRole),
new Claim(ClaimTypes.Email, "[email protected]"),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return await Task.FromResult(AuthenticateResult.Success(ticket));
}
}
}
Posted by Peter Vogel on 11/14/2019