Protecting data
Core has four ways to protect data. Each answers a different question.
| Mechanism | Question it answers | Decided | Server code | API | User |
|---|---|---|---|---|---|
| Code access | Can code set this property? | Compile time | Restricted | Restricted | Restricted |
| Rule access | Is this property locked or hidden for this record right now? | Runtime, per record | ReadOnly and Hidden restrict writes |
Restricted | Hidden is not rendered |
| API exposure | Can API clients touch this entity or property at all? | Compile time | Not restricted | Restricted | Restricted |
| Role access | Is this user allowed? | Runtime, per user | Not restricted | Restricted per role | Restricted per role |
"Restricts server code" means your own business logic. Only code access and rule access stop it. Role access and API exposure apply to API requests only.
Choosing a mechanism
| You want to... | Use |
|---|---|
| Stop all code from assigning a property | Code access |
| Lock properties after a record is posted, closed, or approved | Rule access (ReadOnly) |
| Hide a field that does not apply to the record's current state | Rule access (Hidden) |
| Only allow the client to read a property but server code can set it | API exposure (ReadOnly) |
| Keep an internal entity or property out of the API completely | API exposure (None or Hide) |
| Let some users see or edit a field and not others | Role access |
| Keep a value private from some users | Role access (don't grant the field) |
1. Code access
Plain C# decides who can assign a property. Core generates the property, so use the setter's accessibility.
[Property<DataTypes.Currency>("Balance")]
public partial decimal Balance { get; } //No setter
- Server code, the API, and the UI cannot set the property from outside the class.
- These properties can be dirtied and computed based on changes of another property or running a method. See Computes.
See Properties.
2. Business logic rule access
Business logic decides at runtime, per record, whether a property is read-only or hidden.
[Logic]
public class InvoiceBL(Invoice.Logic invoice)
{
[RegisterLogic]
public void ProtectInvoice()
{
invoice.ReadOnly(i => i.Amount).If(i => i.IsPosted);
invoice.Hidden(i => i.RejectionReason).If(i => i.Status != InvoiceStatus.Rejected);
}
}
| Rule | Effect |
|---|---|
ReadOnly |
Writes are rejected, from server code and from the API. The UI disables the field. |
Hidden |
Same as ReadOnly. The UI also does not render the field, and API responses mask its value. |
- If any condition on a property is true, the rule applies.
- Server code can still read the real value of a hidden property.
- Hidden masks values. It is not security.
$filter,$orderby, and$applystill use real values. Use role access when a value must stay private. - Use property groups to apply one condition to many properties.
3. API exposure
Attributes on the entity and its properties limit what API clients can do. The limit is fixed at compile time and is the same for every user, including administrators.
Prefer no setter. If no code should set a property, remove the setter (see Code access).
[ApiAccess(PropertyAccess.ReadOnly)]only blocks API clients, so server code can still set the property. Use it when server code must set the value but clients must not.
[ApiEntity]
[ApiAccess(EntityAccess.Read | EntityAccess.Update)]
public partial class Transaction
{
[Property<DataTypes.Currency>("Amount")]
[ApiAccess(PropertyAccess.ReadOnly)]
public partial decimal Amount { get; set; }
}
- Clients can read and update Transaction, but cannot create or delete it, or change
Amount. PropertyAccess.Hideremoves the property from API reads and writes.- Server code is not restricted. Your business logic can still set
Amount. - Hidden entities and properties are not included in the meta data.
See API access.
4. Role access
Role-based access control (RBAC) decides per user. Responsibilities grant permissions. Roles hold responsibilities. Users hold roles.
access.AddResponsibility("View transactions", "Read-only access to transactions", grant =>
{
grant.Entity<Transaction>()
.View()
.Read(t => t.Amount)
.Write(t => t.Clear);
});
- Entities, properties, and methods are restricted until a responsibility grants them.
- When a user has several responsibilities, the most permissive setting wins.
- A property is hidden when no responsibility grants it. There is no
Hidegrant.ReadandWriteapply to API requests and to the UI. - Hidden entities and properties are not listed in the metadata. OData requests with hidden elements are refused by the API.
- Row filters (
FilterRows) also limit which rows a user sees. Server logic still sees every row. See Row-level filtering. - The UI needs no extra wiring. It hides or disables what the user cannot use.
- Connected apps (OAuth) add one more layer. A read-only app only gets its user's reads.
- Server code is not restricted.
See RBAC.