Pbac.AspNetCore
1.0.0
See the version list below for details.
dotnet add package Pbac.AspNetCore --version 1.0.0
NuGet\Install-Package Pbac.AspNetCore -Version 1.0.0
<PackageReference Include="Pbac.AspNetCore" Version="1.0.0" />
paket add Pbac.AspNetCore --version 1.0.0
#r "nuget: Pbac.AspNetCore, 1.0.0"
// Install Pbac.AspNetCore as a Cake Addin #addin nuget:?package=Pbac.AspNetCore&version=1.0.0 // Install Pbac.AspNetCore as a Cake Tool #tool nuget:?package=Pbac.AspNetCore&version=1.0.0
Pbac.AspNetCore
Description
A helper library for implementing the permission/attribute based access control (ABAC) with JSON web tokens using the ASP.NET Core's policy-based access control (PBAC).
- Scalable & compact - when converting a permission list to a string, it encodes 4 permissions in a single character (see the implementation details below). This allows you to store up to 1,024 permissions in a single JWT claim in Azure AD B2C, for example.
- Performant and has low memory allocations (see the benchmarks below)
Usage
Create the permissions enum:
public enum Permissions { Create = 0, Read = 1, Update = 2, Delete = 3, }
Note that having the exact underlying value for each permission is important - messing it up will mess the permissions stored!
Also, only enums with the
int
as an underlying type (the default) are currently supported.Set the user permission values inside your identity provider using the
PermissionSet
:user.Claims[ClaimNames.Permissions] = new PermissionSet<Permissions>(new[] { Permissions.Create, Permissions.Read, }) .ToCompactString();
Add the permission policy requirement handler with the same claim name as above:
services.AddPermissionBasedAuthorization<Permissions>(options => options.PermissionsClaimName = ClaimNames.Permissions);
Note that if you re-define the authorization
DefaultPolicy
in your app then the code above should be inserted after your logic to make the permission policies inherit the new default policy.(Optionally) Inherit the
AuthorizePermission<T>
with the specific permissions enum type:public class AuthorizePermissionAttribute : AuthorizePermissionAttribute<Permissions> { public AuthorizePermissionAttribute(Permissions permission) : base(permission) { } }
Or create an extension method if using the Minimal APIs:
public static TBuilder RequirePermission<TBuilder>(this TBuilder builder, Permissions permission) where TBuilder : IEndpointConventionBuilder { if (builder == null) throw new ArgumentNullException(nameof(builder)); return builder.RequireAuthorization(new AuthorizePermissionAttribute<Permissions>(permission)); }
Decorate the controllers/endpoints with the
AuthorizePermission<T>
(or the one created above) attribute:[HttpGet] [Authorize(Permissions.Read)] public IActionResult Get() => Ok();
Or if using the minimal APIs:
app.MapGet("/", () => Results.Ok()) .RequirePermission(Permissions.Read);
Implementation
The permission set is being serialized into a string as a hex number where N-th bit represents the presence of a permission with the underlying value of N.
For example, consider the following permission enum:
public enum Permissions
{
Create = 0,
Read = 1,
Update = 2,
Delete = 3,
Manage = 4,
}
Then, the binary representation of a set containing all permissions above would look like this:
1 F - permission string
┌┬┬┤ ┌┬┬┤
0001 1111 - permission bit values
││││ ││││
7654 3210 - bit positions
└┬┘│ ││││
│ │ │││└ Create
│ │ ││└ Read
│ │ │└ Update
│ │ └ Delete
│ └ Manage
└ Not used
For deserialization, the above is done in the reversed order.
Also, because based on the enum value we can calculate the specific bit position we need to check, we don't need to deserialize the entire string when we verify a single permission.
Benchmarks
Checking a single permission value from the compact string:
Method Mean Error StdDev Allocated PermissionSet_HasPermission 74.17 ns 1.382 ns 1.225 ns - Validating a user has a required permission in their claim list:
Method Mean Error StdDev Allocated PermissionAuthorizationHandlerBenchmark_HandleRequirementAsync 359.4 ns 6.79 ns 13.25 ns 144 B
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
- Microsoft.AspNetCore.Authorization (>= 7.0.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.