Enforcing CRUD and FLS in Apex
Salesforce apps runs under two contexts one is user context and other is system context.
User context is the default context that we see when you’re interacting with the UI in Salesforce, In user context, the current user’s permissions, field-level security, and sharing rules are taken into account as we browse the UI or execute code.
Application executes in user context when:
- A user browses the application via the standard Salesforce-provided UI.
- A user views a Visual force page that uses a standard controller.
- A user views a Visual force page that references objects with standard object notation.
- The platform executes Anonymous Apex via console or API calls.
- An application on the platform makes a standard API call.
System context code executing under this in the platform does not take into account the current user’s permissions, field-level security, and sharing rules during code execution. In this context, applications have access to all objects and fields that are available in the org, including encrypted fields.
The platform executes code in system context in:
- Apex Classes (including web services).
- Apex Triggers.
- Apex web services called from the API
From a security perspective, user context is preferable because user access controls are maintained throughout the transaction. This is why standard pages and Visual force pages built on standard controllers run in user context. But the restrictions of user context aren’t always appropriate for custom business processes and applications.
Lightning Aura Components : CRUD and Field-Level Security (FLS) Aura components don’t automatically enforce CRUD and FLS when you reference objects or retrieve the objects from an Apex controller. This means that the framework continues to display records and fields for which users don’t have CRUD access and FLS visibility.
Use of with sharing keyword in an Apex controller ensures that users see only the records they have access to in an Aura component. we must explicitly check for isAccessible(), isCreateable(), isDeletable(), and isUpdateable() prior to performing operations on records or objects.
//Get list of fields to check field-level read permission before querying for this fields
String [] expenseAccessFields = new String [] {'Id', 'Name','Amount__c', 'Client__c','Date__c','Reimbursed__c', 'CreatedDate'};
Map<String,Schema.SObjectField> m = Schema.SObjectType.Expense__c.fields.getMap();
//Iterate over list of fields to check access
for (String fieldToCheck : expenseAccessFields) {
// Check if the user has access to view field
if (!m.get(fieldToCheck).getDescribe().isAccessible()) {
/**
* Similarly fields can be checked using following methods
* isUpdateable() Checks field-level update permission
* isCreateable() Checks field-level create permission
*/
// Pass error to client
throw new System.NoAccessException();
}
}
//Check object-level permission before deleting a record
if (Schema.sObjectType.Contact.isDeletable()) {
// Delete contact
}
References: