My react application sits behind .net core 2.2
I have it protected via AzureAD
// Sign-in users with the Microsoft identity platform
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("ISINPClient", options));
I add Authorization policy like below. My Auth handler checks if the user has groups in their claims against the ones loaded from the app.settings
itemArray = Configuration.GetSection("AllowedGroups").Get<string[]>();
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddRequirements(new GroupAccessRequirement(itemArray))
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Here is the Authorizationhanlder
public class GroupAccessRequirement : AuthorizationHandler<GroupAccessRequirement>, IAuthorizationRequirement
{
private string[] _groups { get; set; }
public GroupAccessRequirement(string[] groups)
{
_groups = groups;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, GroupAccessRequirement requirement)
{
if (_groups == null)
context.Succeed(requirement);
foreach (var group in _groups)
{
if (context.User.HasClaim(claim => claim.Value == group))
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
In order to force .net core to authenticate with Azure, i have this code below
app.Use(async (context, next) =>
{
if (context.User.Identity.IsAuthenticated == false && context.Request.Path != "/signin-oidc")
{
await context.ChallengeAsync(AzureADDefaults.AuthenticationScheme);
}
else
{
await next.Invoke();
}
});
So at this point i am authenticated.
But i need to force call GroupAccessRequirement to make sure user has group authorization to proceed to SPA.
If you user doesn't have permission which page to show ? SPA or .NET access denied?
Question: How to validate AuthorizationHandler before showing SPA and which Access Denied page to show in SPA or .NET core?
Thank you.
Not sure whether the issue is resolved but I'd like to add my two cents.
If you want to customize that behavior, likely you'll have to:
You might have to pay attention to your api controllers after #2, since you want to return HTTP 403 instead of 302 to the access denied page. Asp.net core tries to return 403 for AJAX requests but based on my experience it might not be enough. You can customize it by setting your own OnRedirectToAccessDenied event - eg return 403 if request URL starts with /api/.
One last thing, relying on getting group membership from the id token might not be a good idea - AAD will send a place holder instead of the real group if a user has many group memberships. The best option is to request for an access token and check against Microsoft Graph API (not AAD Graph which is dying). But it does bring another issue, your app will have to have scopes like Directory.Read.All which requires admin consent. :(
I wish there is a simpler option. Happy to hear more from others.
All in all, I think for SPA application it's better to do authentication from SPA itself. Microsoft has the MSAL.js library which can help with this. It's not perfect but works in most cases. There are many examples - I have some code on github using it as well. It also contains some code to "carry over" asp.net core authorization policies to the client for React app to consume for better user experience. Feel free to check it out.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.