AspNetCore.Authorization.Extender 2.0.3

dotnet add package AspNetCore.Authorization.Extender --version 2.0.3
NuGet\Install-Package AspNetCore.Authorization.Extender -Version 2.0.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AspNetCore.Authorization.Extender" Version="2.0.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AspNetCore.Authorization.Extender --version 2.0.3
#r "nuget: AspNetCore.Authorization.Extender, 2.0.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AspNetCore.Authorization.Extender as a Cake Addin
#addin nuget:?package=AspNetCore.Authorization.Extender&version=2.0.3

// Install AspNetCore.Authorization.Extender as a Cake Tool
#tool nuget:?package=AspNetCore.Authorization.Extender&version=2.0.3

AspNetCore.Authorization.Extender

Enhance your AspNetCore authorization and authentication with permission based authorization rather than basic role based. You can set permission for each endpoint or controller and have more control over it.

Installation

via NuGet

Install-Package AspNetCore.Authorization.Extender

via CLI

dotnet add package AspNetCore.Authorization.Extender

ClaimTypes

// Claim type for endpoint permissions
ExtClaimTypes.EndPointPermissions;
// Claim type for allowing every action, ve careful when using this
// Only recommended to be used in Development environment
ExtClaimTypes.AllPermissions; 

Defining permissions as Enum Type

You can use enum types or strings to define permissions. It's your preference however it will be more manageable if you use enum types.

public enum Permissions
{
    AccessAccountSettings,
    UpdateUser,
    UpdateOtherUsers,
    UpdateUserPassword,
    //... etc.
}

Authentication with Endpoint permissions

RequirePermissionAttribute is used to check if user has permission to access an endpoint.

This is different from role based authorization because instead of assigning multiple roles to each action to allow only specific roles. By using this you can set specific permission for each endpoint and assign those to users.

This gives overall more control over authorization and rather than editing controllers to change who accesses which endpoint.

Implementing permission to an Endpoint

//Action filter that checks if user has permission to access endpoint
[RequirePermission(Permissions.User)] 
public class UserController : Controller {
    [RequirePermission(Permissions.AccessAccountSettings)] 
    public IActionResult AccountSettings(){ /* Your code */}

    [AllowAnonymous]
    public IActionResult Login(){ /* Your code */}
}

Create a Permissions table in your database and always sync this table with your Permissions Enum Type.

Create a Roles table in your database and define roles

Create a RolePermissions table in your database and define which permissions are allowed for each role. (Many to Many relationship)

In your Users table add the role you want to the user.

Once user logins, get all permissions of User's role and create a permission string by using extension methods provided by the library.

Then simply add this to user's claims and you are done.

However keep in mind that once a claim is created it will not be removed until user logs out and logs back in.

Creating user claims

In the example EndPointPermissions are added to claims.

When authenticated user tries to access an endpoint, RequirePermissionAttribute will check if user has permission to access endpoint.

If user does not have permission then 403 Forbidden will be returned.

If user is not authenticated then 401 Unauthorized will be returned.

If permission is set in controller and you want to disable permission for a single action/endpoint you can do it by using AllowAnonymousAttribute which is provided by default

var endpointPermissions = new List<Permissions>(){
    Permissions.AccessAccountSettings,
    Permissions.UpdateUser,
    Permissions.UpdateUserPassword,
    //... etc.
}; // Get permissions from database
// Create claim list
var claimList = new List<Claim>(); 
// Add permissions to claim list merges list with comma (,) separator
claimList.Add(new Claim(EasMeClaimType.EndPointPermissions, endpointPermissions.CreatePermissionString())); 
//Or use extension method
claimList.AddPermissions(endpointPermissions);

//Sign in user or create JWT token with claims
var identity = new ClaimsIdentity(claimList, "login"); // Create identity
var principal = new ClaimsPrincipal(identity); // Create principal
await HttpContext.SignInAsync(principal); // Sign in user

//.. or create JWT token with claims

Creating policies

Library provides few simple extension methods to add RequirePermissionAttribute logic as policies.

Using PolicyNameTemplate

You can pass a list of permissions and a PolicyNameTemplate to create policies.

// Add policy to services
var permissionList = new List<Permissions>(){
    Permissions.AccessAccountSettings,
    Permissions.UpdateUser,
    Permissions.UpdateUserPassword,
    //... etc.
}; // Get permissions from database
services.AddAuthorization(options =>
{
    // Add policy with permission list with a default PolicyNameTemplate of "RequirePermission:{PermissionName}"
    options.AddRequiredPermissionPolicies(permissionList);
    // Or add policy with custom PolicyNameTemplate
    options.AddRequiredPermissionPolicies(permissionList, "CustomPolicyNameTemplate:{PermissionName}");
    
});

Using Dictionary key value pairs as PolicyName and Permission

You can pass a dictionary of PolicyName and Permission to create policies.

// Add policy to services
var policyDictionary = new Dictionary<object, object>(){
    {Policy.RequireAccessAccountSettingsPermission, Permissions.AccessAccountSettings},
    {Permissions.AccessAccountSettings, Permissions.AccessAccountSettings},
    {"CustomPolicyName", Permissions.UpdateUser},
    {"CustomPolicyName", "UpdateUser"}
    //... etc.
    //You can use enum types or strings to define permissions. 
};
services.AddAuthorization(options =>
{
    options.AddRequiredPermissionPolicies(policyDictionary);
});

Extension Methods

// Create permission string from List<string> or List<Enum>
var permissionString = permissions.CreatePermissionString();

//Add permissions to Enumerable<Claim>
var newClaims = claimEnumerable.AddPermissions(permissions); //returns new Claim Enumerable

//Add permissions to List<Claim>
claimList.AddPermissions(permissions);

//Has permission
var hasPermission = HttpContext.User.HasPermission(Permissions.AccessAccountSettings); //bool
//Or
var hasPermission = HttpContext.User.HasPermission("AccessAccountSettings"); //bool

var permissions = HttpContext.User.GetPermissions();//returns List<string> of current users permissions
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.3 219 7/23/2023
2.0.2 182 7/23/2023
2.0.1 191 7/12/2023
2.0.0 183 7/2/2023
1.0.0 201 6/29/2023