Reputation: 2297
I have been trying to add Authorization and permissions to my project.
I have managed to generate the database tables as such:
AspNetRoleClaims
AspNetUserClaims
AspNetRoles
AspNetUsers
ApsNetUserRoles
These tables got generated using PMC, I committed these tables after the blazer web assembly template was used.
In the PMC I entered:
update-database
Which generated those tables described above.
So when i use:
<AuthorizeView Roles="Admin">
<div class="wrapper">
<ContentLayout Title="@_greeting">
<Card>
<CardContent>
Hi @context.User.Identity!.Name
</CardContent>
</Card>
</ContentLayout>
</div>
<div>
</div>
</AuthorizeView>
Works great and only Admin can view the content.
Now what my problem is how do I add Policy-Based Authorisation, I have searched to find a solution but I tried examples but no luck.
What I'm trying to do is find a way of adding Policy-Based Authorization without any logic so it's built-in with this table, is this possible?
Or can someone please share how I can achieve Policy-Based Authorization?
These are the data in the tables:
And what is was trying for Policies:
<AuthorizeView Policy="CanBuy">
<div>hello</div>
</AuthorizeView>
But i get error:
Upvotes: 3
Views: 5376
Reputation: 2738
The accepted answer is NOT good practice.
Here's a better solution that follows the recommended approach for ASP.NET Core and Blazor applications:
Option 1: validating within bootstrapping code; suggest using this with simple validation only.
services.AddAuthorizationCore(options => {
options.AddPolicy("CanBuyPolicy", policy =>
policy.RequireClaim("permission.canbuy", "CanBuy"));
});
OR
services.AddAuthorizationCore(options => {
options.AddPolicy("CanBuyPolicy", policy =>
policy.RequireRole("admin", "user"));
});
Option 2: setup policy handlers, and bootstrap them;
Create a Policy class that does the Authorization Handling of your requirement:
public class UserCanBuyPolicy : IAuthorizationHandler
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context)
{
//claim-based validation
if (context.User.HasClaim("permission.canbuy", "CanBuy"))
context.Succeed(requirement);
//role-based validation
if (context.User.IsInRole("admin") || context.User.IsInRole("user"))
context.Succeed(requirement);
return Task.CompletedTask;
}
}
Then you need to register your policy in your application bootstrapping:
services.AddScoped<IAuthorizationHandler, UserCanBuyPolicy>();
services.AddAuthorizationCore(options => {
options.AddPolicy("CanBuyPolicy", policy => policy.Requirements.Add(UserCanBuyRequirement));
});
The latter option offers more flexibility and can be scaled to include more custom logic as needed.
HTH
Upvotes: 6
Reputation: 6518
You solution makes no sense, since each @if checks for @context.User..., and if that is not null, then user it authenticated, and AuthorizeView is redundand (without policy attribute).
I have just researched this myself, and come up with a solution (add this code in client startup):
services.AddApiAuthorization();
services.AddAuthorizationCore(options =>
{
options.AddPolicy(
"CanBuy",
policy => policy.RequireClaim(
claimType,
claimValue));
});
Putting policy on client only makes no sense, so you would need to do the same on the server side.
Upvotes: 2
Reputation: 2274
I made it work with this.
<AuthorizeView>
@if (@context.User.Claims.Count(c => c.Value == Permissions.Products.Create) != 0)
{
<a class="btn btn-success" href="product/create">Create</a>
}
@if (@context.User.Claims.Count(c => c.Value == Permissions.Products.Edit) != 0)
{
<a class="btn btn-warning">Edit</a>
}
@if (@context.User.Claims.Count(c => c.Value == Permissions.Products.View) != 0)
{
<a class="btn btn-primary" href="product-list">View</a>
}
@if (@context.User.Claims.Count(c => c.Value == Permissions.Products.Delete) != 0)
{
<a class="btn btn-danger">Delete</a>
}
</AuthorizeView>
Please find the repo for your reference. https://github.com/chhinsras/PermissionBlazorApp/blob/master/PermissionBlazorApp/Client/Pages/Product/ProductPage.razor
Upvotes: 1