Defining Responsibilities In Business Logic
Responsibilities are code-defined permission bundles. You define them in [Logic] classes and register them with IResponsibilityRegistry.
Basic pattern
Select entity -> Define entity permissions -> Define property permissions
using Benevia.Core.Annotations;
using Benevia.Core.Permissions;
[Logic]
public class ContactBL(Contact.Logic contact, IResponsibilityRegistry access)
{
[RegisterLogic]
public void CreateContactResponsibilities()
{
access.AddResponsibility("Enter individual", "Limited permissions for creating individual contacts", grant =>
{
grant.Entity<Contact>()
.CreateAndDelete()
.Write(c => new {c.FirstName, c.LastName, c.PrimaryEmail, c.PrimaryPhone, c.MailingAddress})
.Read(c => c.Website);
grant.Entity<Address>()
.View()
.Write(c => new {c.StreetAddress, c.City, c.State, c.PostalCode});
});
access.AddResponsibility("View contacts", "View all contact information", grant =>
{
//...
});
}
//...
}
Entity permissions
Use one of these entry points per entity.
CreateAndDelete()Create(): Entities can be created but not deleted.View(): Entities cannot be created or deleted. Depending on property permissions, it can be edited.
Updates need View() and Write(...) for each supplied field, without Create().
ApiAccess must also allow the operation, even for administrators.
Set property permissions
After setting entity-level access, set property permissions:
Read(...): Set a property or properties to haveReadpermissionsWrite(...): Set a property or properties to haveWritepermissionsReadForAllProperties(): Set all properties on this entity to haveReadpermissions. This does not set method permissions.WriteForAllProperties(): Set all properties on this entity to haveWritepermissions. This does not set method permissions.
grant.Entity<Contact>()
.View() //Cannot create or delete an entity, but can read Guid and Title.
.Write(s => new {s.FirstName, s.LastName, s.PrimaryPhone, s.PrimaryEmail}); //Give permissions to read and write
grant.Entity<Contact>()
.CreateAndDelete()
.Write(c => new {c.FirstName, c.LastName, c.PrimaryEmail, c.PrimaryPhone, c.MailingAddress})
.Read(c => c.Website);
grant.Entity<Address>()
.View()
.ReadForAllProperties(); //This makes all properties readable instead of defining each one.
grant.Entity<SalesOrder>()
.CreateAndDelete()
.Write(o => new {o.DocNumber, o.TransactionDate, o.Description, o.Details})
.Write(o => o.SellToCustomer) //Automatically gives me list access to the Customer entity
.Read(o => o.ShippingMethod); //Automatically gives me reference access to the ShippingMethod entity but not list access.
grant.Entity<PriceLevel>()
.View() //Gives reference and list access.
.Read(m => m.Name);
Set method permissions
Control callable methods independently from property permissions:
AllowMethod(...): Gives access to run a method or a list of methods by passing the name of the method.AllowAllMethods(): Gives access to run all methods in this entity.
grant.Entity<Product>()
.AllowMethod(p => p.GetPrice); //Pass name of method -- not p.GetPrice()
Row-level filtering
By default, rows are not restricted. You can constrain visible rows:
grant.Entity<Proposal>()
.View()
.FilterRows((query, userContext) =>
query.Where(c => c.SalesPerson.User.Id == userContext.Id));
Require other responsibilities
Use grant.Requires(...) to declare that one responsibility builds on another. The permissions from the required responsibility are automatically included when evaluating access.
Requires(name): Adds a single named responsibility as a dependency.Requires(name1, name2, ...): Adds multiple responsibilities as dependencies.
access.AddResponsibility("Modify contacts", "Create and modify contact information", grant =>
{
grant.Requires("View contacts"); // Inherits all permissions from "View contacts"
grant.Entity<Contact>()
.CreateAndDelete()
.WriteForAllProperties();
});
This is useful when one responsibility extends another — the user only needs to be assigned the more permissive responsibility, rather than both.