Provide permissions to the Framework
This guide is only useful if you want to understand the internal permissions mechanism between the Framework and the UserPermissions module or if you want to develop your own permissions module in case you do not use the UserPermissions module.
The Framework does not know the permissions of the current user because the permissions are managed on the side of the generated application (they are stored in the application database).
When an operation that requires permissions is executed, the framework asks the application for the permissions related to functions that are tied to the requested resource(s).
To provide permissions to the Framework, you have to implement the IPermissionLoader interface in a business assembly.
public class PermissionLoader : IPermissionLoader
{
public PermissionDefaultBehavior DefaultBehavior
{
get { return PermissionDefaultBehavior.Deny; }
}
public async Task<Dictionary<string, Permission>> GetPermissionsAsync(string[] functionNames)
{
// ...
}
}
Don't forget to register the implementation in the service collection. You must add the following code to the Startup.cs file :
public static class Startup
{
public static void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<IPermissionLoader, PermissionLoader>();
}
}
Set default behavior
The DefaultBehavior property defines the behavior that the Framework should have in the case that there are no permission(s) linked to the requested function(s).
By default, the resource will be denied.
You can make the default behavior permissive by setting the DefaultBehavior property to Allow. In this case, the resource will be allowed.
In the case where there is no implementation of the IPermissionLoader interface, the Framework considers that it is an application in development so everything is allowed.
Implement permission retrieval
The logic for retrieving the current user's permissions must be done in the GetPermissionsAsync method.
A basic implementation of this method can be as follows :
public async Task<Dictionary<string, Permission>> GetPermissionsAsync(string[] functionNames)
{
// Get the current user (via the `IUserInfoAccessor` interface).
// Retrieve the user role.
string userRole = "Storekeeper";
// Retrieve the permissions of the requested functions according to the user's role.
IEnumerable<IPermissionView> rolePermissions = await _permissionViewRepository
.GetQuery()
.Where(p => p.UserRole == userRole && functionNames.Contains(p.FunctionName))
.ToListAsync();
Dictionary<string, Permission> permissions = [];
foreach (IPermissionView rolePermission in rolePermissions)
{
if (rolePermission.PermissionType == PermissionType.AllowDeny)
{
permissions.Add(rolePermission.FunctionName, new AllowDenyPermission(rolePermission.Allow));
}
if (rolePermission.PermissionType == PermissionType.CRUD)
{
permissions.Add(rolePermission.FunctionName, new CrudPermission(rolePermission.AllowCreation, rolePermission.AllowReading, rolePermission.AllowUpdate, rolePermission.AllowDeletion));
}
}
return permissions;
}
This method is called when :
- An API is executed.
- A user opens the client application (to get the permissions related to the client side resources).
This method can be called many times, that's why it is important to set up a cache to avoid having to make too many requests to the database. The cache must be implemented on this side to let you have the full control over it: define the key of the cached items (by role or by user for example), invalidate the cache (when the permissions of a role change for example), ...