More Related Content
Similar to Force.com canvas入門ガイド
Similar to Force.com canvas入門ガイド (20)
More from Kazuki Nakajima
More from Kazuki Nakajima (20)
Force.com canvas入門ガイド
- 2. Agenda
• Force.com Canvasとは?
• 単純なiFrameとの違い
• 接続アプリケーションの作成
• 組織における接続アプリケーションのアクセス設定
• Signed Request(署名付き要求)を使った認証方法
• シングルサインオン
• Force.comへのAPIコール
• VisualforceへのCanvasの埋め込み
• フレームのリサイズ
• Canvasアプリのパッケージング
• 参考情報
- 4. 単純なiFrameとの違い
• 外部アプリにはセッションIDではなく認証トークンが含まれたSigned Requestを送信できる。Signed
Requestは秘密 によって署名されているため途中の経路での改ざんや偽装を防止することができる。
• 認証トークンはOAuth2.0 Webフローでも取得できるが、複数回のリダイレクトが必要。Signed Request
を利用すればリダイレクトが不要になる。
!
!
!
!
!
!
!
• セッションIDは常にログインユーザーのフルアクセス権限が与えられてしまうが、Signed Requestに含まれ
る認証トークンでは必要な範囲に権限を限定することができる。
• Canvasアプリはどのユーザーがアクセスできるか、組織の管理者が設定可能。
Force.com 外部アプリ
①iFrameのコンテンツ要求と同時に
Signed Request送信
②APIコール
アクセストークン
Signed Requestのフロー
Force.com 外部アプリ
①iFrameのコンテンツ要求
OAuth2.0 Webフロー
②認証サーバへのリダイレクト
③認証後アクセスコードと共に
リダイレクト
④トークンの要求
⑤トークン送信
⑥APIコール
- 5. 接続アプリケーションの作成
• Canvasアプリはこの接続アプリケーションを作成した組織、またはインストールした組織で利用可能になる。
• 接続アプリケーションは開発者がこのアプリの名前、秘密 、権限範囲、外部アプリのURLや認証方式を定義す
るためのもの。
• 作成手順
• ビルド > 作成 > アプリケーションで、「接続アプリケーション」のセクションで「新規」ボタンをクリック
• 基本情報セクションを適当に入力
• OAuth設定セクションで「OAuth設定の有効化」にチェック => 認証方式にSigned Requestを利用する場合はOAuthの認
証フローは利用しませんが、このチェックにより生成されるConsumer Secretは依然として必要になるためチェックしま
す。
• コールバックURLを「sfdc://success」と設定 => ダミーです。Signed Request方式では実際には利用されません。
• 選択したOAuth範囲を必要に応じて追加
• サポートされているアプリケーション種別セクションでForce.com Canvasにチェック
• キャンバスアプリケーションのURLに外部アプリのトップURLを入力 => URLはhttpsが必要です。
• アクセス方法を署名付き要求(POST)に設定 => 後述のSigned Request方式を指定しています。
• 場所をCanvasアプリを表示させる場所に応じて設定
- 8. Signed Requestを使った認証方法(続き)
• 外部アプリはこのリクエストを受け取り、 Consumer Secretを用いてこのリクエストが想
定されるForce.comアプリからのものであること、改ざんがないことを検証する。
• Canvas RequestをConsumer SecretをキーとしてHMAC SHA-256でハッシュ化し、Base64エン
コードをおこなう
• 上記値を受信したハッシュと比較し、等しければ検証は成功。
<?php
// Signed Requestを.で分割
$sr_r = explode('.', $_POST["signed_request"], 2);
!
// Canvas RequestをConsumer SecretをキーにしてHMAC SHA-256でハッシュ化。さらにBase64エンコード。
$calculated_value = base64_encode(hash_hmac("sha256", $sr_r[1], YOUR_CONSUMER_SECRET, true));
!
// 算出した値と、POSTリクエストに含まれていたハッシュ値を比較して検証
if ($sr_r[0] == $calculated_value){
return true; // 合格
} else {
return false; // 不合格
}
?>
*サーバー側のサンプルコードはPHPを利用しています。
- 9. Signed Requestを使った認証方法(続き)
• 外部アプリはCanvas RequestをBase64デコードし、APIコールに必要なトークン、インス
タンスURLをはじめ必要な情報を取得することができる。
<?php
// Signed Requestを.で分割
$sr_r = explode('.', $_POST["signed_request"], 2);
!
// Canvas RequestをBase64デコードし、canvas_requestオブジェクトとして取得
$canvas_request = json_decode(base64_decode($sr_r[1]));
!
// Javascriptから利用するためにJSON形式のままの変数を用意
$canvas_request_in_json = base64_decode($sr_r[1]);
!
// APIアクセスに必要なアクセストークン、インスタンスURLは下記のように取得
$oauthToken = $canvas_request->client->oauthToken;
$instanceUrl = $canvas_request->client->instanceUrl;
?>
- 10. Signed Requestを使った認証方法(続き)
• Signed Requestが送信されるのはChatterタブのCanvas Appをクリックしたとき、およ
びCanvasアプリが含まれるVisualforceページを表示させたときのみです。Canvasアプリ
内のリンクをクリックしたときには送信されません。後続のリクエストに備えて外部アプリは
Canvas Requestを何らかの形でセッションに保存しておく必要があります。
• Safari等一部のブラウザはiFrame内からのCookieを拒絶するため、Canvas Requestの保
持にCookieが利用できないケースがあります。サーバー側で全リンクにセッションIDを自動
挿入する機能や、HTMLコンテンツ内にセッションIDを埋め込むなどのワークアラウンドを検
討してください。(例えばPHPではsession.use_trans_sidを有効にすることでCookieを
用いずにセッションの保持が可能)
iFrame
Cookie
- 12. シングルサインオン(続き)
• Signed Requestを活用すればシンプルなSSOが可能。*またはSAMLを用いたSSOも構築可能
• あらかじめ外部アプリ側のアカウント情報にSalesforceユーザー名をマッピングしておく。*外部アプリ
のユーザー名とSalesforceユーザー名が一致している場合には必要ありません。
!
!
!
!
!
!
!
!
!
• 外部アプリ側で通常どおりSigned Requestを検証する。
• Canvas Requestから抽出したSalesforceユーザー名を外部アプリ側のアカウント情報から検索。
ヒットすればそのユーザーですでに認証されていると見なしてセッションを発行する。
username password salesforce_username
nakajima@mydom.com 90dfoj4BnM knakajima@sf.mydom.com
yamashita@mydom.com kd8FIKJef8e tyamashita@sf.mydom.com
追加
外部アプリのアカウント情報
- 13. シングルサインオン(続き)
• Sample Code
<?php
// Signed Requestを.で分割
$sr_r = explode('.', $_POST["signed_request"], 2);
!
// Canvas RequestをConsumer SecretをキーにしてHMAC SHA-256でハッシュ化。さらにBase64エンコード。
$calculated_value = base64_encode(hash_hmac("sha256", $sr_r[1], YOUR_CONSUMER_SECRET, true));
$canvas_request = json_decode(base64_decode($sr_r[1]));
!
// 算出した値と、POSTリクエストに含まれていたハッシュ値を比較して検証
if ($sr_r[0] == $calculated_value){
// ローカルデータベース(PostgreSQL)から該当するユーザーを検索
$dbconn = pg_connect(YOUR_CONNECTION_STRING);
$query = "select * from users where salesforce_username = '" . $canvas_request->context->user->userName . "'";
$result = pg_query($query);
$result_all = pg_fetch_all($result);
if (isset($result_all[0]["username"])){
// SSO成功
session_start();
$_SESSION["username"] = $result_all[0]["username"];
$_SESSION["canvas_request"] = $canvas_request;
return true;
} else {
// Signed Requestの検証は成功しているが、SSOは失敗
return false;
}
} else {
return false; // 不合格
}
?>
- 15. Force.comへのAPIコール(続き)
• Force.com Canvas SDKをインポート
<script src="<?php echo $sr->canvas_request->client->instanceUrl;?>/canvas/sdk/js/<?php echo
$sr->canvas_request->context->environment->version->api; ?>/canvas-all.js"></script>
<script type="text/javascript">
var canvas_request = JSON.parse('<?php echo $canvas_request_in_json; ?>');
var url = '/services/data/v' + canvas_request.context.environment.version.api + '/query?
q=SELECT+ID,NAME+FROM+ACCOUNT';
Sfdc.canvas.client.ajax(
url,
{
client: canvas_request.client,
method: 'GET',
contentType: 'application/json',
success: function(data){
if (data.status === 200){
console.log(data.payload.records);
} else {
console.log(data.statusText);
}
}
}
);
</script>
• APIコール(取引先データ取得)
- 16. Force.comへのAPIコール(続き)
<script type="text/javascript">
var canvas_request = JSON.parse('<?php echo $canvas_request_in_json; ?>');
var body = {Name: "Test Account"};
var url = '/services/data/v' + canvas_request.context.environment.version.api + '/sobjects/
Account';
Sfdc.canvas.client.ajax(
url,
{
client: canvas_request.client,
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(body),
success: function(data){
if (data.status === 201){
console.log('SUCCESS');
} else {
console.log(data.statusText);
}
}
}
);
</script>
• APIコール(取引先データ作成)
- 17. Force.comへのAPIコール(続き)
<script type="text/javascript">
var canvas_request = JSON.parse('<?php echo $canvas_request_in_json; ?>');
var body = {Name: "Test Account"};
var record_id = ''; // 更新する取引先のレコードIDをセット
var url = '/services/data/v' + canvas_request.context.environment.version.api + '/sobjects/
Account/' + record_id;
Sfdc.canvas.client.ajax(
url,
{
client: canvas_request.client,
method: 'PATCH',
contentType: 'application/json',
data: JSON.stringify(body),
success: function(data){
if (data.status === 204){
console.log('SUCCESS');
} else {
console.log(data.statusText);
}
}
}
);
</script>
• APIコール(取引先データ更新)
- 18. Force.comへのAPIコール(続き)
<script type="text/javascript">
var canvas_request = JSON.parse('<?php echo $canvas_request_in_json; ?>');
var body = {Name: "Test Account"};
var record_id = ''; // 削除する取引先のレコードIDをセット
var url = '/services/data/v' + canvas_request.context.environment.version.api + '/sobjects/
Account/' + record_id;
Sfdc.canvas.client.ajax(
url,
{
client: canvas_request.client,
method: 'DELETE',
contentType: 'application/json',
data: JSON.stringify(body),
success: function(data){
if (data.status === 204){
console.log('SUCCESS');
} else {
console.log(data.statusText);
}
}
}
);
</script>
• APIコール(取引先データ削除)
- 19. Visualforceへの埋め込み
• Canvasアプリの表示場所はChatterタブ、またはVisualforceページ
• VisualforceページではCanvas用のタグを用いて全体あるいは一部にCanvasアプ
リを配置可能
* VisualforceはAPIバージョン27.0以上が必要です。
* パッケージとして配布する場合、必ずnamespacePrefix属性とdeveloperName属性を指定してください。
* applicationName属性も同時に指定した方が表示が若干速くなります。
* parameters属性で指定した値はcanvas_request->context->environment->parametersで取得できま
す。
* apex:canvasAppの完全な属性リストはVisualforce開発者ガイドの標準コンポーネントを参照ください。
// デフォルトでheightは900px、widthは800pxになります
<apex:canvasApp namespacePrefix="myprefix" applicaitonName="My App" developerName="myapp" />
!
// parametersで任意の値をCanvas Requestに含めることができます。
<apex:canvasApp namespacePrefix="myprefix" applicaitonName="My App" developerName="myapp"
parameters="{p1:'value1',p2:'value2'}" />
- 21. フレームのリサイズ(続き)
Sfdc.canvas(function(){
sr = JSON.parse('<?php echo $canvas_request_in_json; ?>');
!
// フレームを縦横ともにコンテンツに応じて自動でリサイズする。デフォルトでは300msごとにコンテンツサイズの検出
がおこなわれる。
Sfdc.canvas.client.autogrow(sr.client);
!
// 検出間隔を100msにセットして自動リサイズ
Sfdc.canvas.client.autogrow(sr.client, true, 100);
!
// 検出と自動リサイズを無効にする
Sfdc.canvas.client.autogrow(sr.client, false);
});
* HTMLでフレームサイズをheight, widthで指定しても自動リサイズ機能はフレームサイズを動的に変更しますが、maxHeight,
maxWidthで指定したフレームサイズを超えることはありません。
- 23. 参考情報
• Force.com Canvas SDK開発者ガイド
• http://developerforcejp.s3.amazonaws.com/developer/docs/platform_connect/
canvas_framework.pdf
• DeveloperforceのCanvasまとめサイト
• http://wiki.developerforce.com/page/Force.com_Canvas
• Force.com Canvas SDKのリファレンス
• http://htmlpreview.github.io/?https://raw.github.com/forcedotcom/
SalesforceCanvasJavascriptSDK/master/docs/index.html
• Force.com Canvas Toolkit for PHP(サーバー側でのSigned Requestの取
り扱いをまとめたツールキット。Herokuでも利用可能)
• https://github.com/nkjm/Force.com-Canvas-Toolkit-for-PHP