🛡️ Implement a Permission System
In this step we'll extend the Potato.Examples solution with a basic permission model. The goal is to restrict access to nodes in the tree using PermissionNode and ReferenceNode.
1. 📦 Add Domain Models
Inside Potato.Examples.Domain/Entities add two new records:
ReferenceNode.cs
namespace Potato.Examples.Domain;
public record ReferenceNode(
Guid? Id,
Guid? ParentId,
Guid ReferenceId
) : Node(Id, ParentId, DisplayName: null);
PermissionNode.cs
namespace Potato.Examples.Domain;
public record PermissionNode(
Guid? Id,
Guid? ParentId,
Guid ReferenceId,
bool CanRead,
bool CanWrite,
bool CanDelete,
bool CanPermit,
bool CanRevoke
) : Node(Id, ParentId)
{
public static readonly PermissionNode NoPermissions = new(null, null, Guid.Empty, false, false, false, false, false);
public bool MeetsRequirements(PermissionsRequirements req) =>
(!req.Read || CanRead) &&
(!req.Write || CanWrite) &&
(!req.Delete || CanDelete) &&
(!req.Permit || CanPermit) &&
(!req.Revoke || CanRevoke);
}
Add an enum to the same folder:
PermissionsRequirements.cs
namespace Potato.Examples.Domain;
public record PermissionsRequirements(
bool Read = false,
bool Write = false,
bool Delete = false,
bool Permit = false,
bool Revoke = false
);
2. 🧩 Querying with Permissions
Use the helper methods in PotatoPermissionService and PotatoPermissionFilters to resolve and check permissions.
Example usage inside a query handler:
var permissions = await PotatoPermissionService.FindPermissions(tree, references, subjectNode);
var hasAccess = PotatoPermissionService.MeetsRequirements(permissions, subjectNode, new PermissionsRequirements(Read: true));
You can also filter search results:
var results = await finder.Find(
PotatoPermissionFilters.OnlyNodesWithPermission(permissions, new PermissionsRequirements(Read: true)),
cursor
);
✅ Summary
You now have:
- Permission and reference nodes in your domain
- A simple requirements model
- Examples of resolving and evaluating permissions
➡️ Next: Working with S3 Files