Newer Version Available
Enforce Field-Level Security With the stripInaccessible Method (Beta)
The field- and object-level data protection is accessed through the Security and SObjectAccessDecision classes. The access check is based on the field-level permission of the current user in the context of the specified operation - create, read, update, or upsert. The stripInaccessible method checks the source records for fields that don’t meet field-level security check for the current user and creates a list of sObjects. The return list is identical to the source records, except that the fields that are inaccessible to the current user are removed. The sObjects returned by the getRecords method contain records in the same order as the sObjects in the sourceRecords parameter of the stripInaccessible method. Fields that aren’t queried are null in the return list, without causing an exception.
To identify inaccessible fields that were removed, you can use the isSet method. For example, the return list contains Contact object and the custom field social_security_number__c is inaccessible to the user. Because this custom field fails the field-level access check, the field is not set and isSet returns false.
1SObjectAccessDecision securityDecision = Security.stripFields(sourceRecords);
2Contact c = securityDecision.getRecords()[0];
3System.debug(c.isSet('social_security_number__c')); // prints "false"The following are some examples where the stripInaccessible method can be used.
Example
1Security.SObjectAccessDecision securityDecision =
2 Security.stripInaccessible(AccessType.READABLE,
3 [SELECT Name, BudgetedCost, ActualCost FROM Campaign];
4 );
5
6 // Construct the output table
7 if (securityDecision.getRemovedFields().get('Campaign').contains('ActualCost')) {
8 for (Campaign c : securityDecision.getRecords()) {
9 //System.debug Output: Name, BudgetedCost
10 }
11 } else {
12 for (Campaign c : securityDecision.getRecords()) {
13 //System.debug Output: Name, BudgetedCost, ActualCost
14 }
15}Example
1List<Account> accountsWithContacts =
2 [SELECT Id, Name, Phone,
3 (SELECT Id, LastName, Phone FROM Account.Contacts)
4 FROM Account];
5
6 // Strip fields that are not readable
7 SObjectAccessDecision decision = Security.stripInaccessible(
8 AccessType.READABLE,
9 accountsWithContacts);
10
11// Print stripped records
12 for (Integer i = 0; i < accountsWithContacts.size(); i++)
13 {
14 System.debug('Insecure record access: '+accountsWithContacts[i]);
15 System.debug('Secure record access: '+decision.getRecords()[i]);
16 }
17
18// Print modified indexes
19 System.debug('Records modified by stripInaccessible: '+decision.getModifiedIndexes());
20
21// Print removed fields
22 System.debug('Fields removed by stripInaccessible: '+decision.getRemovedFields());Example
1List<Account> newAccounts = new List<Account>();
2Account a = new Account(Name='Acme Corporation');
3Account b = new Account(Name='Blaze Comics', Rating=’Warm’);
4newAccounts.add(a);
5newAccounts.add(b);
6
7SObjectAccessDecision securityDecision = Security.stripInaccessible(
8AccessType.CREATABLE,
9newAccounts);
10
11// No exceptions are thrown and no rating is set
12insert securityDecision.getRecords();
13
14System.debug(securityDecision.getRemovedFields().get('Account')); // Prints "Rating"
15System.debug(securityDecision.getModifiedIndexes()); // Prints "1"Example
1String jsonInput =
2'[' +
3'{' +
4'"Name": "InGen",' +
5'"AnnualRevenue": "100"' +
6'},' +
7'{' +
8'"Name": "Octan"' +
9'}' +
10']';
11
12List<Account> accounts = (List<Account>)JSON.deserializeStrict(jsonInput, List<Account>.class);
13SObjectAccessDecision securityDecision = Security.stripInaccessible(
14AccessType.UPDATABLE,
15accounts);
16
17// Secure update
18update securityDecision.getRecords(); // Doesn’t update AnnualRevenue field
19System.debug(String.join(securityDecision.getRemovedFields().get('Account'), ', ')); // Prints "AnnualRevenue"
20System.debug(String.join(securityDecision.getModifiedIndexes(), ', ')); // Prints "0”