Upload
terrasky
View
322
Download
1
Embed Size (px)
Citation preview
ねらい
• Dreamforceセッション
「Secure Coding:
Field-level Security, CRUD, and Sharing」
より、
今回は、画面開発に絞って、CRUDとFLSを遵守する術を再度確認します。
2
まず、大前提として・・・
Apex:
Apex Classes do not enforce CRUD
Why? System Context
Visualforce:
Visualforce Pages do enforce CRUD
Why?User Context
11
まず、大前提として・・・
Apex:
Apex は、CRUDもFLSも遵守しません。
システムコンテクストだから。
Visualforce:
Visualforce は、CRUDもFLSも遵守します。
ユーザコンテクストだから。
12
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
2. データに対する変更(作成、更新、削除)
14
更に、ここもポイントは2つ。
① Visualforce層を介する場合
② Visualforce層を介さない場合
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
15
更に、ここもポイントは2つ。
① Visualforce層を介するとは?
差込項目が、Sobjectや項目を直接参照
しているケース。
Visualforce Page
01 <apex:page standardController="Account">
02 <apex:pageBlock title="Contacts">
03 <apex:dataTable value="{!account.Contacts}" var="contact" cellPadding="4"
border="1">
04 <apex:column>
05 <apex:facet name="header">Name</apex:facet>
06 {!contact.Name}
07 </apex:column>
08 <apex:column>
09 <apex:facet name="header">Phone</apex:facet>
10 {!contact.Phone}
11 </apex:column>
12 </apex:dataTable>
13 </apex:pageBlock>
14 </apex:page>
16
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
17
更に、ここもポイントは2つ。
① Visualforce層を介する場合
② Visualforce層を介さないとは?
文字列、整数、Apex クラスなどのオブ
ジェクトを介して SObject データを参照
している場合
Visualforce Page
01 <apex:page controller="MyLanguageController" showheader="false"
applyBodyTag="true" sidebar="false">
02 <apex:pageMessages />
03
04 <apex:form >
05 <apex:selectList value="{!selectedLanguage}" multiselect="False" size="1"
style="width:115px;">
06 <apex:selectOptions value="{!languageOptions}"/>
07 </apex:selectList>
08 <apex:commandButton value="change!" action="{!save}" />
09 </apex:form>
10
11 </apex:page>
18
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
19
① Visualforce層を介する場合
⇒CRUD、FLSが自動チェックされる。
② Visualforce層を介さない場合
⇒CRUD、FLSの自動チェックはない。
よって、自前でチェックする必要
がある!
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
2. データに対する変更(作成、更新、削除)
21
ここも同様のポイントが2つ。
① Visualforce層を介する場合
② Visualforce層を介さない場合
考えるべきポイントは2×2
2. データに対する変更(作成、更新、削除)
22
① Visualforce層を介する場合
⇒CRUD、FLSが自動チェックされる。
② Visualforce層を介さない場合
⇒CRUD、FLSの自動チェックはない。
よって、自前でチェックする必要
がある!
考えるべきポイントは2×2
1. ユーザに対して表示するデータ
2. データに対する変更(作成、更新、削除)
23
いずれのパターンにおいても、
Visualforce層を介するレンダリングが推
奨される。
Visualforce Page
01 <apex:page controller="RandomContactController">
02 <apex:outputText value="{!getRandomName}" />
03 </apex:page>
28
Apex Controller
01 public with sharing class RandomContactController {
02 public String getGetRandomName() {
03
04 Contact [] myList = [SELECT Name FROM Contact LIMIT 1000];
05 // Pick a list entry at random
06 Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size());
07 Contact selected = myList.get(index);
08 return selected.Name;
09 }
10 }
Visualforce Page
01 <apex:page controller="RandomContactController">
02 <apex:outputText value="{!getRandomName}" />
03 </apex:page>
29
Apex Controller
01 public with sharing class RandomContactController {
02 public String getGetRandomName() {
03
04 // Check if the user has read access on the Contact.Name field
05 if (!Schema.sObjectType.Contact.fields.Name.isAccessible()) {
06 return '';
07 }
08
09 Contact [] myList = [SELECT Name FROM Contact LIMIT 1000];
10 // Pick a list entry at random
11 Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size());
12 Contact selected = myList.get(index);
13 return selected.Name;
14 }
15 }
Visualforce Page
01 <apex:page standardcontroller="Lead" extensions="LeadConverterExtension">
02 <apex:pageMessages />
03 <apex:pageBlock title="Lead">
04 <apex:outputField value="{!Lead.Name}" /><br />
05 <apex:outputField value="{!Lead.Company}" /><br />
06 <apex:outputField value="{!Lead.Phone}" /><br />
07 <apex:form>
08 <apex:commandButton action="{!convertLead}" value="Convert To Contact" />
09 </apex:form>
10 </apex:pageBlock>
11 </apex:page>
31
32
Apex Controller
01 public with sharing class LeadConverterExtension {
02 private Lead l;
03 public LeadConverterExtension(ApexPages.StandardController ctr) {
04 l = [SELECT FirstName,LastName,Phone,Company FROM Lead WHERE Id=:ctr.getRecord().Id];
05 }
06
07 public PageReference convertLead() {
08 Contact c =
new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone);
09 insert c;
10 return null;
11 }
12 }
33
Apex Controller
01 public with sharing class LeadConverterExtension {
02 private Lead l;
03 public LeadConverterExtension(ApexPages.StandardController ctr) {
04 l = [SELECT FirstName,LastName,Phone FROM Lead WHERE Id=:ctr.getRecord().Id];
05 }
06
07 public PageReference convertLead() {
08 String [] contactUpdateFields = new String []
{'FirstName', 'LastName', 'Phone'};
09
10 Map<String,Schema.SObjectField> m = Schema.SObjectType.Contact.fields.getMap();
11 for (String fieldToCheck : contactUpdateFields) {
12 if (!m.get(fieldToCheck).getDescribe().isCreateable()) {
13 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'Insufficient access'));
14 return null;
15 }
16 }
17
18 Contact c =
new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone);
19 insert c;
20 return null;
21 }
22 }
35
Apex Controller
01 public with sharing class LeadConverterExtension {
02 private Lead l;
03 public LeadConverterExtension(ApexPages.StandardController ctr) {
04 l = [SELECT FirstName,LastName,Phone FROM Lead WHERE Id=:ctr.getRecord().Id];
05 }
06
07 public PageReference convertLead() {
08 String [] contactUpdateFields = new String []
{'FirstName', 'LastName', 'Phone'};
09
10 Map<String,Schema.SObjectField> m = Schema.SObjectType.Contact.fields.getMap();
11 for (String fieldToCheck : contactUpdateFields) {
12 if (!m.get(fieldToCheck).getDescribe().isCreateable()) {
13 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'Insufficient access'));
14 return null;
15 }
16 }
17
18 Contact c =
new Contact(FirstName = l.FirstName, LastName = l.LastName, Phone = l.Phone);
19 insert c;
20 return null;
21 }
22 }
isCreateable() を
isUpdateable() に
してチェック!
Visualforce Page
01 <apex:page standardcontroller="Lead" extensions="LeadDeleteExtension">
02 <apex:pageMessages />
03 <apex:pageBlock title="Lead">
04 <apex:outputField value="{!Lead.Name}" /><br />
05 <apex:outputField value="{!Lead.Company}" /><br />
06 <apex:outputField value="{!Lead.Phone}" /><br />
07 <apex:form>
08 <apex:commandButton action="{!deleteLead}" value=“Delete" />
09 </apex:form>
10 </apex:pageBlock>
11 </apex:page>
37
38
Apex Controller
01 public with sharing class LeadDeleteExtension {
02 private Lead l;
03 public LeadDeleteExtension(ApexPages.StandardController ctr) {
04 l = [SELECT Id FROM Lead WHERE Id=:ctr.getRecord().Id];
05 }
06
07 public PageReference deleteLead() {
09 delete l;
10 return null;
11 }
12 }
39
Apex Controller
01 public with sharing class LeadDeleteExtension {
02 private Lead l;
03 public LeadDeleteExtension(ApexPages.StandardController ctr) {
04 l = [SELECT Id FROM Lead WHERE Id=:ctr.getRecord().Id];
05 }
06
07 public PageReference deleteLead() {
08 if (!Lead.sObjectType.getDescribe().isDeletable()) {
09 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'Insufficient access'));
10 return null;
11 }
12 }
13
14 delete c;
15 return null;
16 }
17 }
isDeletable() は オブジェクトレベルで
チェック!
Visualforce Page
<!– 表示権限チェック -->
01 <apex:outputText value="{!contactName}"
02 rendered="{!$ObjectType.Contact.fields.Name.Accessible}" />
<!– 作成権限チェック -->
01 <apex:inputText value="{!stringToBecomeNewContactEmail}"
02 rendered="{!$ObjectType.Contact.fields.Email.Createable}" />
<!– 更新権限チェック -->
01 <apex:inputText value="{!contactEmail}"
02 rendered="{!$ObjectType.Contact.fields.Email.Updateable}" />
<!– 削除権限チェック -->
01 <apex:commandButton action="{!CustomDelete}“
02 rendered="{!$ObjectType.Contact.Deletable}" />
41