Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/f1x3d/pbac.aspnetcore
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)
https://github.com/f1x3d/pbac.aspnetcore
abac access aspnet aspnetcore auth authorization csharp dotnet dotnet-core jwt pbac permissions ukrainian
Last synced: about 2 months ago
JSON representation
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)
- Host: GitHub
- URL: https://github.com/f1x3d/pbac.aspnetcore
- Owner: f1x3d
- License: apache-2.0
- Created: 2023-07-16T14:18:14.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-09-08T12:38:38.000Z (4 months ago)
- Last Synced: 2024-11-01T14:19:07.282Z (2 months ago)
- Topics: abac, access, aspnet, aspnetcore, auth, authorization, csharp, dotnet, dotnet-core, jwt, pbac, permissions, ukrainian
- Language: C#
- Homepage:
- Size: 38.1 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Pbac.AspNetCore
[![NuGet](https://img.shields.io/nuget/v/Pbac.AspNetCore?logo=nuget&label=NuGet)](https://nuget.org/packages/Pbac.AspNetCore)
## Description
A helper library for implementing the [permission/attribute based access control (ABAC)](https://en.wikipedia.org/wiki/Attribute-based_access_control) with [JSON web tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) using the ASP.NET Core's [policy-based access control (PBAC)](https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies).
* Scalable & compact - when converting a permission list to a string, it encodes 4 permissions in a single character ([see the implementation details below](#implementation)). This allows you to store [up to 1,024 permissions](https://learn.microsoft.com/en-us/graph/api/resources/extensionproperty?view=graph-rest-1.0#properties) in a single JWT claim in Azure AD B2C, for example.
* Performant and has low memory allocations ([see the benchmarks below](#benchmarks))## Usage
1. Create the permissions enum:
```csharp
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.
1. Set the user permission values inside your identity provider using the `PermissionSet`:
```csharp
user.Claims[ClaimNames.Permissions] = new PermissionSet(new[]
{
Permissions.Create,
Permissions.Read,
})
.ToCompactString();
```1. Add the permission policy requirement handler with the same claim name as above:
```csharp
services.AddPermissionBasedAuthorization(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.
1. (Optionally) Inherit the `AuthorizePermission` with the specific permissions enum type:
```csharp
public class AuthorizePermissionAttribute : AuthorizePermissionAttribute
{
public AuthorizePermissionAttribute(Permissions permission)
: base(permission)
{ }
}
```Or create an extension method if using the Minimal APIs:
```csharp
public static TBuilder RequirePermission(this TBuilder builder, Permissions permission)
where TBuilder : IEndpointConventionBuilder
{
if (builder == null)
throw new ArgumentNullException(nameof(builder));return builder.RequireAuthorization(new AuthorizePermissionAttribute(permission));
}
```1. Decorate the controllers/endpoints with the `AuthorizePermission` (or the one created above) attribute:
```csharp
[HttpGet]
[Authorize(Permissions.Read)]
public IActionResult Get()
=> Ok();
```Or if using the minimal APIs:
```csharp
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 |