Force.com canvas入門ガイド
-
Upload
kazuki-nakajima -
Category
Documents
-
view
4.375 -
download
2
description
Transcript of Force.com canvas入門ガイド
中嶋 一樹テクニカルエバンジェリスト
@nkjm
Force.com Canvas入門ガイド
@nkjm
Agenda• Force.com Canvasとは?
• 単純なiFrameとの違い
• 接続アプリケーションの作成
• 組織における接続アプリケーションのアクセス設定
• Signed Request(署名付き要求)を使った認証方法
• シングルサインオン
• Force.comへのAPIコール
• VisualforceへのCanvasの埋め込み
• フレームのリサイズ
• Canvasアプリのパッケージング
• 参考情報
Force.com Canvasとは?
• 外部サーバーで提供されるWebアプリをForce.comの画面に組み込み、統合されたアプリとして提供するためのフレームワーク
• 画面を組み込むためにiFrameを利用。ただしフレームサイズを動的に変更するためのSDKを提供しているため自然な画面表示が可能。
• 外部サーバーはForce.comのAPIを利用してデータベースにアクセスする。SDKがこのAPIアクセスをサポートする。
• APIの利用に必要となる認証に"Signed Request"という手法を用いてよりシンプルでセキュアな認証を可能にしている *OAuth 2.0も選択可能
Force.com 外部アプリ
iFrameSDKによる動的リサイズ
単純な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コール
接続アプリケーションの作成• 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アプリを表示させる場所に応じて設定
組織における接続アプリケーションのアクセス設定
• 組織内のどのユーザーがこのCanvasアプリにアクセスできるのかを設定する。
• 設定手順
• 管理 > アプリケーションを管理する > 接続アプリケーションで作成した接続アプリを選択• OAuthポリシーセクションの許可されているユーザーを「管理者が承認したユーザーは事前承認済み」に設定して保存
• 関連リストのプロファイルまたは権限セットで、Canvasアプリにアクセスを許可す
るプロファイル/または権限セットを追加する
* この設定はあくまでこの組織内で有効な設定であり、パッケージには含めることはできません。
Signed Request(署名付き要求)を使った認証方法• 外部アプリはForce.comにAPIアクセスするための認証情報(トークン)が必要だが、この認証情報を含め
ユーザーに関する情報をForce.comから外部アプリに初回の1リクエストで伝送する効率的な仕組み
• Force.comから外部アプリには下記のフォーマットのデータ(Signed Request)を伴ったPOSTリクエス
トが送信される。dfj984ropjdjflsdf.09wjefokjljlsdfpjdogodjfgpsdjgdsgjlkdsjgf(以後省略)
ハッシュ Canvas Request
デリミター(ドット)アプリの情報、ユーザーの情報、トークンなどがJSON形式で格納されておりそれをBase64エンコードした値
Canvas RequestをConsumer SecretをキーとしてHMAC SHA-256でハッシュ化、さらにBase64エンコードした値
Force.com 外部アプリ
①ユーザーがCanvasアプリにアクセス
②Signed Requestを伴ったPOSTリクエスト
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を利用しています。
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;?>
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
シングルサインオン
• 外部アプリ側でもデータベース等のリソースを保持しそのアクセスに認証が必要な場
合、シングルサインオン(SSO)をおこなうことがのぞましい。
Signed Requestに含まれるトークンでアクセス可能 別途認証し、セッションを確立する必要がある
Force.com 外部アプリ
シングルサインオン(続き)
• Signed Requestを活用すればシンプルなSSOが可能。*またはSAMLを用いたSSOも構築可能
• あらかじめ外部アプリ側のアカウント情報にSalesforceユーザー名をマッピングしておく。*外部アプリ
のユーザー名とSalesforceユーザー名が一致している場合には必要ありません。
• 外部アプリ側で通常どおりSigned Requestを検証する。
• Canvas Requestから抽出したSalesforceユーザー名を外部アプリ側のアカウント情報から検索。
ヒットすればそのユーザーですでに認証されていると見なしてセッションを発行する。
username password salesforce_username
[email protected] 90dfoj4BnM [email protected]
[email protected] kd8FIKJef8e [email protected]
追加
外部アプリのアカウント情報
シングルサインオン(続き)• 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; // 不合格}?>
Force.comへのAPIコール• Force.comへはクライアント側(Javascript)、サーバ側、双方からAPIコール可能。
• クライアント側についてはクロスドメインアクセスとなるが、SDKを利用することでアクセス可
能となる。
Force.com 外部アプリ
クライアント側(Javascript)からのAPIコール(SDKがサポート)*Javascriptは外部アプリからロードしたものなのでForce.comにアクセスするとクロスドメインアクセス(通常ブラウザによりブロックされる)になるが、SDKに含まれるProxy機能がこれを可能にしている。
サーバー側からのAPIコール
Canvas Requestから取得したアクセストークン
サーバーから間接的に受け取ったアクセストークン
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コール(取引先データ取得)
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コール(取引先データ作成)
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コール(取引先データ更新)
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コール(取引先データ削除)
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'}" />
フレームのリサイズ
• iFrameはHTMLの仕様上サイズを静的に指定する必要があり、動的なコンテンツを表示させた
場合スクロールバーが多重に表示される、またはコンテンツが途中で切れるといった現象が発
生しユーザービリティを損なう。
• SDKのautogrow(), resize()メソッドを利用することで、コンテンツに応じてフレームサイ
ズを動的に変更し、上記の問題を解消できる。
height=400px width=750pxとしたCanvasアプリの出力結果
自動リサイズ無効 自動リサイズ有効
フレームのリサイズ(続き)
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で指定したフレームサイズを超えることはありません。
Canvasアプリのパッケージング• 管理パッケージに接続アプリケーションを含めることでCanvasアプリが配布可能になる
• ユーザー組織では接続アプリケーションのアクセス設定をおこなう必要がある
• 接続アプリケーションの定義を変更した場合は、パッケージを転送アップグレードすることで
即座にユーザー環境に変更を反映可能 *アプリケーションパートナーのみ
組織A 組織B 組織C開発組織(Developer Edition)
管理パッケージ
接続アプリケーション
ユーザー組織
インストール
参考情報
• 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
Developer Forceのソーシャルメディアをフォロー
@developerforcejp/ #forceotcomjp
Developer Force Japan
+Developer Force Japan
Developer Force Japan