Update - I now believe combining @Michael Washington Azure AD Groups solution with my custom AuthorizationHandler solution is the best of both worlds. I don't have an example of it, but if you are going down this path, look in to it.
Edited Heavily as question "evolved"
Ecom / Blazor Server site - Need a simple way to do non-authenticated public pages, user specific profile pages and authorized only admin pages. Different page elements will be visible depending on Authentication and Authorization status. Would like to use AD B2C and asp.net core identity decoration for simplicity (ex - [Authorize(Roles = "Administrator")]).
To allow public pages anyone can access -> remove the default policies in Program.cs
To only show pages or elements to authenticated users -> use [Authorize] and AuthorizeView
To do b2c, VERY basic roll authorization, create a custom user attribute field on your B2C tenant (ex. isAdmin) and return it on all User Flows. In your code, create a custom AuthorizationHandler that checks the Claims token data returned from the UserFlow for the custom attribute. Then declare the custom Handler in the Program.cs and give it a custom policy declaration. You can now use it just like any .net core identity decoration (or so I think).
Sample code
-- Create a CustomAuthorization.cs class file --
// poc example to match a user name to give page / component authorization
public class CustomAuthorization : IAuthorizationRequirement
{
public string _myUserName;
public CustomAuthorization(string myUserName)
{
_myUserName = myUserName.ToLower();
}
}
public class myCustomAuthorizationRequirementHandler : AuthorizationHandler<CustomAuthorization>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthorization requirement)
{
string? LoggedInName = context.User.Identity?.Name; // example of getting the display name
var FirstName = context.User.Claims.FirstOrDefault(
c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname")?.Value; // example of getting the given name
if (LoggedInName is null) { }
else if (LoggedInName.ToLower() == requirement._myUserName) // useless example of checking if the display name equals the requirement
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
-- In Program.cs --
// in the "AddAuthorization" section add
options.AddPolicy("UserNameDodger", policy => policy.Requirements.Add(new CustomAuthorization("Dodger")));
//under that section add
builder.Services.AddSingleton<IAuthorizationHandler, myCustomAuthorizationRequirementHandler>();
-- On any RazorPage --
@attribute [Authorize(Policy = "UserNameDodger")]
---------
Still missing:
- how to set a custom b2c attribute for the user (may have to use MS graph similar to ADefWebserver's example below but hopefully I can manually set it in Azure).
- how to redirect someone if they reach a location they need authorization for but don't have it (currently just says "not authorized")
HUGE thanks to @Michael Washington and many others who helped me get to this solution. I could completely be missing something, but I think this is going to work really well for me.