Salesforceのデータアクセス権について（内部ユーザ編）

Salesforceのデータ共有について、まとめて整理しておりました。
内部ユーザに向けてのデータアクセス権をこの文章でまとめて一括で説明していきたいです！
## Salesforceにアクセス権を制御できるのは
Salesforceにアクセス権を制御できるのは以下の３つです。
　・オブジェクトレベル
　・レコードレベル
　・項目レベル
ではアクセス権についての話だと、以下の図はきっと見たことがあるでしょう。この図は一体何の意味でしょうか、またはこれらのアクセス権はお互いにどう影響するかは本文章で説明致します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/3c9c272e-8118-eb8a-0df0-3c1842b721f5.png)
## ３つアクセス権はお互いにどう影響するか
アクセス権を設計するには以下の順番で考慮する必要があります。
```
オブジェクト　＞　レコード　＞　項目
```
つまり、
・オブジェクトのアクセス権を付与しないと、レコードアクセス権をや項目レベルアクセス権をいくら付与しても意味がありません。
・レコードアクセス権を付与しないと、項目レベルアクセス権をいくら付与しても意味がありません。
では順次に説明しましょう。
## オブジェクトのアクセス権
権限を設計する時に、まず考慮すべきなのはオブジェクトアクセス権限です。オブジェクトアクセス権限は権限の大元です。それ以降の権限設定はオブジェクトアクセス権限を越えることができませんから。
作成と削除の権限はプロファイルと権限セットのみ制御できますので、作成と削除権限を検討する場合、プロファイルと権限セットだけを考慮して頂ければ問題ないでしょう。
以下のシナリオで説明致します。
##### ◆想定シナリオ
以下の４名内部ユーザがあります。４名ユーザはプロファイルが別々で、それぞれプロファイルに対し、TestObjの権限は以下のように設定するとします。
組織デフォルトの共有設定や共有ルールなどのレコードアクセス権限の設定は一切ない、又はデフォルトのままとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/39302f4d-2337-5acf-7e47-f7b111d177ad.png)
上記の例で、各ユーザがTestObjデータに対し、以下のような権限を持っています。
```
・AさんはTestObjデータが１件も見れません。所有者が自分になっているデータも、組織デフォルトの共有設定や共有ルールなどを利用して参照権限を付与しても、１件も見れません。	
・BさんはTestObjデータが参照権限のみ持っています。所有者が自分になっているデータも、例え組織デフォルトの共有設定や共有ルールなどを利用して編集をを付与しても、参照権限のみになります。	
・CさんはTestObjデータが参照と編集権限を持っています。	
　　所有者が自分になっているデータが必ず参照、編集できますが、
　　他のユーザが所有しているデータに対し、参照、編集できるかどうかは組織デフォルトの共有設定によります。
　　※上記の例で組織デフォルトの共有設定はデフォルトのままなので、現時点Cさんは全TestObjに対し、参照、編集権限を持っています。
```
現時点はオブジェクト権限しかないので、まだまだ理解できると思いますが、レコードレベルのアクセス権を追加してどうなるでしょう。
## レコードレベルのアクセス権
レコードへのユーザーアクセスを制限する唯一の方法は「組織全体のデフォルト設定」です。組織全体のデフォルト設定は、ユーザーがお互いのレコードにアクセスするデフォルトのレベルを指定します。
組織全体のデフォルト設定はオブジェクト単位で制御しています。オブジェクトにより、いくつかの制御がありますが、以下の３つを中心に説明致します。
<b>※前提：TestObjオブジェクトを例として、オブジェクト権限は参照、編集権限を持っているとします。</b>
<b>・非公開：</b>
　　　所有者が自分になっているTestObjデータのみ、参照と編集権限を持っています。
　　　それ以外のTestObjデータはアクセス権を持っていません。
<b>・公開/参照のみ：</b>
　　　所有者が自分になっているTestObjデータのみ、参照と編集権限を持っています。
　　　それ以外のTestObjデータは参照権限のみ持っています。
<b>・公開/参照・更新可能：</b>
　　　所有者が自分になっているにも関わらず、全てのTestObjデータが参照と編集権限を持っています。

オブジェクト権限は権限の大元と異なり、共有ルールなどを利用して、組織全体のデフォルト設定の権限より広い権限を超えることができます。
つまり、Salesforceのレコードレベルの権限計算は組織デフォルトの共有設定や共有ルールなどの権限を全部スキャンして一番広い権限をユーザに付与します。
続きまして、上記の例で組織デフォルトの共有設定や共有ルールを追加して、それぞれの権限はどうなるかを見てみましょう。
※条件付き共有ルールを例として説明致しますが、他の共有ルールは同様な考えです。
##### ◆想定シナリオ
以下の４名ユーザを公開グループに割り当てします。該当公開グループを共有先として、条件付きの共有ルールを作成します。権限を説明するため、共有条件を省略して、共有データがある前提とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/a3d1576f-881e-cec1-eec3-b40abeb46ea9.png)
これをベースにして、以下の共有設定を設定した後に、各ユーザのアクセス権を確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/6575e829-875d-1e80-c56e-cb7604849be2.png)
```
・Aさんに対し、オブジェクト権限を持っていないため、レコード共有権限の設定をしても、参照することできません。
・Bさんに対し、参照のみのオブジェクト権限をもっているため、レコード共有権限を設定しても、編集権限を持つことができません。
・Cさん、Dさんに対し、レコード共有権限を設定することで、他人が所有しているデータの参照、編集権限を制御することができます。
```
レコードレベルのアクセス権を制御できる手段に対し、それぞれを説明致します。
#### ◆ロール階層（Role Hierarchy）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>ロール階層は、組織全体のデフォルト設定に関係なく、データの所有者の上位ロールユーザはその所有者と同じデータにアクセスできるようにします。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>ロール階層の許可は制御できます。階層を使用したアクセス許可がONの場合だけは上記の権限設定が継承されます。<br>※標準オブジェクトはチェックOFFできません</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>上位ロールのユーザへレコード共有を設定する時に利用します。</td>
  </tr>
</table>

#### ◆レコード所有者に基づく共有ルール（Owner-Based Sharing Rules）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>レコード所有者に基づく共有ルールは、レコードの所有者に基づいています。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>所有者の所属がロール、ロール＆下位ロール、公開グループのみ条件として利用できます。</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>ロールや公開グループに基づいてのデータ共有する時に利用します。<br>※例：日本が所有しているデータをアメリカロールユーザへ共有する時</td>
  </tr>
</table>

#### ◆条件付き共有ルール（Criteria-Based Sharing Rules）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>条件付き共有ルールは、レコードの項目に基づいてアクセスを提供します。条件が満たされる場合、共有レコードが作成されます。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>該当オブジェクトの項目は条件として利用できます。<BR>※暗号化された項目は条件として利用できません。</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>データの項目値により、レコード共有を設定する時に利用します。</td>
  </tr>
</table>

#### ◆チーム（Teams）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>レコードの所有者は、所有する各レコードに対してチームを構築することができます。<BR>レコードの所有者はチームメンバーを追加し、各チームメンバーがレコードに対して持つアクセスレベルを指定します。<BR>※標準のチームは：取引先、商談、ケース３つです。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>所有者、上位ロールの人、および管理者のみがチームメンバーを追加し、メンバーへのより多くのアクセス権限を提供することができます。<BR>参照編集権限を持っているチームメンバーはすでに参照権限を持っているユーザのみチームメンバーとして追加できますが、<BR>チームメンバーはそれらのメンバーに追加のアクセス権を付与することはできません。<BR>※つまり、参照編集権限を持っているチームメンバーは参照権限を持っていないユーザがチームメンバーとして追加できません。</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>取引先、商談、ケースに対し、共同利用する時に利用します。</td>
  </tr>
</table>

#### ◆手動共有（Manual Sharing）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>レコードの所有者は、手動共有を使用して、他の方法でアクセス権がないユーザに参照・更新権限を付与することができます。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>手動共有はオブジェクトのページレイアウトにある「共有」ボタンを使用して、参照編集権限を付与します。<BR>※組織の共有設定にデフォルトの内部アクセス権とデフォルトの外部アクセス権が両方「公開/参照・更新可能」の場合、共有ボタン非表示になります。<BR>※レコードの所有者または組織の共有設定が変更される時に、手動共有が削除されません。<BR>※手動共有はSalesforce Classicのみ使えます</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>上記のレコード共有設定で全部対応できない時に利用します。</td>
  </tr>
</table>

#### ◆Apex共有（Programmatic Sharing）
<table>
  <tr>
    <th> 共有仕組み </th>
    <td>手動共有でも要件を満たせない場合、Apexコードを使用して、他の方法でアクセス権がないユーザに参照・更新権限を付与することができます。</td>
  </tr>
  <tr>
    <th> 共有条件 </th>
    <td>オブジェクトのページレイアウトにある「共有」ボタン以外に、トリガーなども、参照編集権限を付与することができます。<BR>※レコードの所有者または組織の共有設定が変更される時に、Apex共有が削除されません。<BR>ただし、Apex共有理由を設定することで、レコードの所有者を変更しても、Apex共有が維持することができます。<BR>※Apex共有理由を設定するのにSalesforce Classicに切り替える必要があります。</td>
  </tr>
  <tr>
    <th> 利用想定 </th>
    <td>上記のレコード共有設定で全部対応できない時に利用します。</td>
  </tr>
</table>

#### ◆Apex共有（Programmatic Sharing）
経験したことがありませんので、ここで省略致します。有識者がいれば、補足して頂ければ助かります。

#### ◆暗黙共有（Implicit Sharing）
暗黙の共有は自動的です。これをオフにすることもオンにすることもできませんが、レコード共有に対し、どんな時に、自動的にアクセス権を付与するかを理解する必要かと思いますので、説明致します。
<table>
  <tr>
    <th> 親の暗黙共有 </th>
    <td>ユーザが商談、ケース、取引先責任者、注文に対し、アクセス権を持っている場合、それに関連する取引先も暗黙共有により、アクセス権も持っています。<BR>※上記の<B>標準オブジェクト限定</b>で、ユーザがカスタム子オブジェクトに対し、アクセス権を持っている場合、それに関連する取引先や他の親カスタムオブジェクトも暗黙共有しません。</td>
  </tr>
  <tr>
    <th> 子の暗黙共有 </th>
    <td>取引先の<b>所有者</b>は、子オブジェクト（商談、ケース、取引先責任者限定）のアクセス権を暗黙共有されます。<BR>※これも<B>標準オブジェクト限定</b>で、カスタムオブジェクトには適用されません。</td>
  </tr>
  <tr>
    <th> 参照関係暗黙共有 </th>
    <td>特にありません。<BR>親オブジェクトのみアクセス権を持っている場合、子オブジェクトのデータが参照できません。<BR>子オブジェクトのみアクセス権を持っている場合、子オブジェクトのページレイアウトに親項目が非表示となり、親オブジェクトのデータが参照できません。</td>
  </tr>
  <tr>
    <th> 主従関係暗黙共有 </th>
    <td>主従関係となる子オブジェクトの共有設定は「親レコード連動」のみになります。つまり、親のアクセス権は子オブジェクトに適用されます。<BR>なので、子オブジェクトに複数の主従関係項目が存在する場合、全部の親がアクセス権を持たないと、子オブジェクトデータが参照できません。</td>
  </tr>
</table>

## 項目レベルアクセス権
項目レベルアクセスを制御できるのはプロファイルと権限セットのみになりますので、項目レベルアクセス権を検討する場合、プロファイルと権限セットだけを設定していればいいでしょう。
ただし、項目レベル以外に画面に表示したくないとかの要望があるかと思いますので、よくあるパターンを上げてみます。
<B>・データにより、表示内容を制御したい：</B>
　レコードタイプ毎にページレイアウトを割り当てすることで実現できます。
<B>・プロファイルまたはアプリケーションにより、表示内容を制御したい：</B>
　プロファイル毎にLightningレコードページを割り当てすることで実現できます。
<B>・一定な条件により、表示内容を制御したい：</B>
　Lightningレコードページの動的フォームを利用して、制御したい項目に表示条件を追加することで実現できます。
<B>・デバイスにより、表示内容を制御したい：</B>
　Lightningレコードページの動的フォームを利用して、PC端末で表示する項目を設定し、レコード詳細-モバイルを利用して、モバイルで表示する項目を設定することで実現できます。

## カスタム開発によるアクセス権の制御
カスタム開発する時にsalesforceのアクセス権を継承して開発したい場合、
#### ・Schema.DescribeSObjectResult、Schema.DescribeFieldResult
Schema.DescribeSObjectResult、Schema.DescribeFieldResultを利用することで、現在のユーザのオブジェクトアクセス権と項目レベルのアクセス権を確認できます。
```
例：
１、取引先責任者のメール項目の更新権限を確認する時、
　　「Schema.sObjectType.Contact.fields.Email.isUpdateable()」を利用します。
２、取引先責任者のオブジェクトレベルの削除権限を確認する時、
　　「Schema.sObjectType.Contact.isDeletable()」を利用します。
※Visualforceページにもこれを使用して、表示制御できます。
```
#### ・Security.stripInaccessible()
stripInaccessible メソッドを使用して、項目およびオブジェクトレベルのデータ保護を適用します。ユーザがアクセスできない項目およびリレーション項目を除外できます
#### ・WITH SECURITY_ENFORCED
SOQLに「WITH SECURITY_ENFORCED」を使用して、同様に項目およびオブジェクトレベルのデータ保護を適用します。
#### ・With Sharing
レコードレベルのアクセス権を考慮する場合、Apexクラスに「With Sharing」を追加することで、共有ルールが適用されます。
※テストクラスのRunAS()を使用して、レコードレベルのアクセス権を確認することが来ます。
<B>補足</B>開発時に上記を利用するする場合、一部の制限があります。詳細はsalesforceヘルプドキュメントを参照して頂ければと思います。


## 参照リンク
A GUIDE TO SHARING ARCHITECTURE
https://resources.docs.salesforce.com/latest/latest/en-us/sfdc/pdf/sharing_architecture.pdf

共有ルールの適用
https://developer.salesforce.com/docs/atlas.ja-jp.244.0.apexcode.meta/apexcode/apex_security_sharing_rules.htm

オブジェクト権限と項目権限の適用
https://developer.salesforce.com/docs/atlas.ja-jp.244.0.apexcode.meta/apexcode/apex_classes_perms_enforcing.htm

stripInaccessible メソッドによるセキュリティの適用
https://developer.salesforce.com/docs/atlas.ja-jp.244.0.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm

WITH SECURITY_ENFORCED を使用した SOQL クエリの絞り込み
https://developer.salesforce.com/docs/atlas.ja-jp.244.0.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm