YIHAA! 😉 (This thing does work!)
and adds Role Authorization to the -Greeter -gRPC -Service:
Server/Startup.cs
endpoints
.MapGrpcService<GreeterService>()
.RequireAuthorization(new AuthorizeAttribute { Roles = "Administrator"})
.EnableGrpcWeb();
I've also added a Client/Claims.razor page with a list of the current user's claims.
It uses Kestrel as the default webserver, a SQLite database and is "CTRL-F5'able" without any further configuration.
You can delete de SQLite database and migrations folder if you want and use the following commands in Visual Studio's Package Manager Console to re-create the db.
- Add-Migration InitialCreate
- Update-Database
At first run the app will create 2 users (if they don't exist, see: Server/SeedData.cs)
admin@example.com
/Qwerty1234#
user@example.com
/Qwerty1234#
and 2 roles:
- Users
- Administrators
The 'Administrators' & 'Users' roles will be assigned to: admin@example.com
The 'Users' role will be assigned to: user@example.com
I've extended ASP.NET Identity AspNetUsers table with an extra 'CustomClaim' field (see: Server/Models/ApplicationUser.cs). I want to use that (auto seeded) CustomClaim
value in the client but haven't figured out how to do that.
Server/Models/ApplicationUser.cs
namespace BlazorTemplate.Server.Models
{
public class ApplicationUser : IdentityUser
{
public string CustomClaim { get; set; }
}
}
Server/Data/SeedData.cs
// Create Administrator
ApplicationUser admin = await UserManager.FindByEmailAsync("admin@example.com");
if (admin == null)
{
admin = new ApplicationUser()
{
UserName = "admin@example.com",
Email = "admin@example.com",
CustomClaim = "AdminClaim" // CustomClaim Value
};
await UserManager.CreateAsync(admin, "Qwerty1234#");
}
// Add Roles
await UserManager.AddToRoleAsync(admin, "Administrators");
await UserManager.AddToRoleAsync(admin, "Users");
To use Name and Role claims with API authorization and Identity Server you can use one of the following approaches (MS Docs)
- API authorization options
- Profile Service
I'm using the (first) 'API authorization options' now but I've included Server/ProfileService.cs and included (commented) code in Server/Startup.cs to use that, but I haven't got it working yet.
Server/ProfileService.cs
namespace BlazorTemplate.Server
{
public class ProfileService : IProfileService
{
public ProfileService()
{
}
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
context.IssuedClaims.AddRange(nameClaim);
var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
context.IssuedClaims.AddRange(roleClaims);
return Task.CompletedTask;
}
public Task IsActiveAsync(IsActiveContext context)
{
return Task.CompletedTask;
}
}
}
Server/Startup.cs
///
// Or this (Use a Profile Service)
// Roles seem to work, Client displays them, but I can't add a Role: 403 Forbidden, Test with gRPC Authorization (Role=Administrators) as well.
// See: https://docs.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/hosted-with-identity-server?tabs=visual-studio#profile-service
///
//services.AddIdentityServer()
// .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
//services.AddTransient<IProfileService, ProfileService>();