項目レベルとオブジェクトレベルのセキュリティや安全なナビゲーション演算子を使ってみる
学習の目的
この単元を完了すると、次のことができるようになります。
- Apex で項目レベルとオブジェクトレベルのセキュリティを適用する。
- 安全なナビゲーション演算子を使用して Null ポインタ例外を回避する。
Security.StripInaccessible を使用して項目レベルとオブジェクトレベルのセキュリティを適用する
新機能
項目レベルとオブジェクトレベルのデータ保護の Security.stripInaccessible
メソッドが Spring '20 で正式リリースされました。このため開発者が、実行ユーザにアクセス権のないすべての項目をレコードから削除できます。セキュリティ違反時に項目に失敗するのではなく、項目を省略するようにして、アプリケーション動作のグレースフルデグラデーションを簡単に可能にします。
そのしくみ
stripInaccessible
メソッドを使用して、クエリやサブクエリの結果から現在のユーザがアクセスできない項目を削除します。このメソッドを使用すると、DML 操作の前に sObject からアクセスできない項目を削除して、例外を回避できます。また、stripInaccessible
メソッドを使用して、信頼されないソースからの並列化された sObject をサニタイズします。
stripInaccesible
メソッドは、ソースレコードに現在のユーザの項目レベルとオブジェクトレベルのセキュリティチェックに失敗した項目がないか確認し、sObject の戻り値リストを作成します。この戻り値リストはソースレコードと同じですが、現在のユーザがアクセスできない項目が除外されている点のみが異なります。
例:
次の例では、現在のユーザに更新アクセス権のない項目がクエリ結果から削除されます。
-
SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.UPDATABLE, [SELECT Name, BudgetedCost, ActualCost FROM Campaign]; );
次の例では、クエリを実行して、アクセスできない項目がクエリ結果から削除されます。
List<Contact> records = [SELECT Id, Name, Phone, HomePhone FROM Contact]; SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE, records);
詳細と例については、次のリソースを参照してください。
- Apex 開発者ガイド: stripInaccessible メソッドによるセキュリティの適用
- Apex 開発者ガイド: Security クラス
- Apex 開発者ガイド: SObjectAccessDecision クラス
- Apex 開発者ガイド: AccessType 列挙
安全なナビゲーション演算子を使用して Null ポインタ例外を回避する
新機能
null 参照の明示的な順次チェックの代わりに、安全なナビゲーション演算子 (?.
) を使用します。この新しい演算子は、null 値を操作しようとする式を除外し、NullPointerException を発生させずに null を返します。
そのしくみ
チェーン式の左側が null に評価されると、右側は評価されません。安全なナビゲーション演算子 (?.
) は、メソッド、変数、プロパティチェーニングで使用します。評価されない式の部分に、変数参照、メソッド参照、配列式などが含まれることがあります。
例:
次の例では、まず a を評価し、a が null の場合は null を返します。それ以外の場合は、戻り値が a.b になります。
a?.b // Evaluates to: a == null ? null : a.b
詳細と例については、『Apex 開発者ガイド』の「安全なナビゲーション演算子」を参照してください。
開発者向けのすばらしい新機能をすべて確認したところで、最後に下記のハンズオン Challenge でこれらの機能を試してみてください。
リソース
- Salesforce: 開発者ガイド: Security クラス
- Salesforce ヘルプ: Winter ’21 リリースノート: 安全なナビゲーション演算子を使用した Null ポインタ例外の回避
ハンズオン Challenge の準備
下記のハンズオン Challenge では、新しい Apex 機能を操作したり、Security.StripInassessible
や安全なナビゲーション演算子を使用したりすることができます。ただし、開始する前に、少しだけ設定が必要です。
ここでのビジネス目標は、システム管理者のみが顧客の機密情報にアクセスでき、機密データを処理する API を他のユーザが呼び出せないようにすることです。コードが概ね安全であることを確認するために、項目レベルとオブジェクトレベルのセキュリティを実行時にチェックする必要があります。開発者は、システム管理者が定義したセキュリティの制約にコードが従っていることを具体的に確認する必要があります。ここでは顧客の機密データを保存する Top Secret (極秘) カスタムオブジェクトを作成します。標準ユーザはこのオブジェクトにアクセスできません。
ハンズオン Challenge に使用する組織を起動し、次の手順を実行します。
- 取引先責任者オブジェクトに、機密データや守秘データを保持する新しいカスタム項目を作成します。
- 項目の表示ラベル: Top Secret (極秘)
- データ型: テキスト
- 項目名: Top_Secret
- 文字数: 255
- 項目レベルセキュリティを定義するときに、[標準ユーザ] プロファイルの [参照可能] ボックスをオフにします。
これで設定は完了です。
Apex クラスの以下のコードブロックを使用してハンズオン Challenge に取り組みます。このコードは、SOQL クエリの前に従来の Schema.SObjectType
の項目レベルとオブジェクトレベルのセキュリティアクセスチェックで安全が確保されています。このコードを Security.stripInaccessible
による簡略化された実装にリファクタリングして、項目レベルとオブジェクトレベルのセキュリティを適用します。さらに、安全なナビゲーション演算子を使用して、結果に Null 値がないか確認します。
ApexSecurityRest コードブロック:
@RestResource(urlMapping='/apexSecurityRest') global with sharing class ApexSecurityRest { @HttpGet global static Contact doGet() { Id recordId = RestContext.request.params.get('id'); Contact result; if (recordId == null) { throw new FunctionalException('Id parameter is required'); } if (Schema.SObjectType.Contact.isAccessible() && Schema.SObjectType.Contact.fields.Name.isAccessible() && Schema.SObjectType.Contact.fields.Top_Secret__c.isAccessible() ) { List<Contact> results = [SELECT id, Name, Title, Top_Secret__c, Account.Name FROM Contact WHERE Id = :recordId]; if (!results.isEmpty()) { result = results[0]; if (Schema.sObjectType.Contact.fields.Description.isUpdateable()){ result.Description = result.Account.Name; } } } else { throw new SecurityException('You don\'t have access to all contact fields required to use this API'); } return result; } public class FunctionalException extends Exception{} public class SecurityException extends Exception{} }
(以下の行番号を示す複製スクリーンショットビューで、書式とインデントを確認できます。)