開発担当の梅です。今回の記事では、PHPでのSaleForceのOAuth 2.0 JWT認証方法(SandBox環境で検証済み)をご紹介いたします。
Salesforceは世界シェアNo.1の営業支援・CRMツールとして、顧客管理、案件管理、見込み客管理、売上予測、レポートとダッシュボードなど様々な機能が利用でいます。Salesforceの情報を自社システムに同期したいという場合、どうしたらいいでしょうか?
Salesforceはサーバ間のデータ交換でREST APIとSOAP APIを用意してありまして、今回の記事はそれらのWeb サービス APIを利用するためのOAuth 2.0 JWT認証方法を説明します。
目次はこちら
- 1. OpenSSLで非公開鍵と自己署名デジタル証明書を作成する
- 2. Salesforce接続アプリケーションを作成する
- 3. PHPでJWTを作成する
- 4. PHPでアクセストークンを取得する
- 5. PHPでSaleForceから情報を取得する
OpenSSLで非公開鍵と自己署名デジタル証明書を作成する
この証明書は、OAuth 2.0認証で、Salesforceに渡したJWTが有効かどうかを検証するためのものです。基本的にはSalesforceの開発者ガイド「非公開鍵と自己署名デジタル証明書の作成」を参照すれば問題なく作成できます。
作業手順1.非公開鍵を生成し、server.key というファイルに保存します。
openssl genrsa -des3 -passout pass:任意のパスワード -out server.pass.key 2048 openssl rsa -passin pass:任意のパスワード -in server.pass.key -out server.key
作業手順2.server.key ファイルを使用して、証明書署名要求を生成します。server.csr というファイルに証明書署名要求を保存します。
openssl req -new -key server.key -out server.csr Country Name (2 letter code) [XX]:JP <- 会社が所在する国を示す2文字のコード。日本の場合、値はJPです。 State or Province Name (full name) []:Tokyo <- 都道府県 Locality Name (eg, city) [Default City]:Taito <- 市区町村 Organization Name (eg, company) [Default Company Ltd]:tatsuno joho system <- 会社名(任意) Organizational Unit Name (eg, section) []: <- 部署名(任意) Common Name (eg, your name or your server's hostname) []:lms.quizgenerator.net <- 一般名(任意) Email Address []:k.bai@tatsuno-system.co.jp <- メールアドレス(任意) A challenge password []: <- 不要 An optional company name []: <- 不要
作業手順3.server.key および server.csr ファイルから自己署名デジタル証明書を生成します。server.crt というファイルに証明書を保存します。
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
コマンドを実行したパスの直下に、次のように4つのファイルが生成されますが、その中に必要となるのは「server.key」と「server.crt」です。
server.pass.key
server.key
server.csr
server.crt
プライマリキー(署名用)「server.key」の中身はこんな感じです。
-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA09nuSOujeZ0AyR8gZ0jg0MOftWUD64IVJcIrULNCdv5/ZQ8H lvf6lOCs/77FWej07XZaNsBTpllX+yZSs3iFY+VZN/xW+6/e6+vARfPUL6IjnRIp drjXIj811qkvfeWXnZmJQgI7EurhwBgg2Oy2rcZFRL+KJGLhgD9cTkGr06dCIU/B ...省略... QYimkGrlPOzEcFEg/Md3n8UwZ7CSHIG0+xPp/8vnpqNmDPOCw7iEI4iJIyBuTkH4 wzKOvJECgYAJ3ORif2l5LT4KCi5UZL27myUGqyDyt5VPa6H/RB3TChKtpnVcBBDF dCnvFqMv+AC3F2xFpcr3HK2l1H8Ya6yy7QMP9fqgHPWKrkpUSZcT/QvZniCreGsS 7jbhD4R4VOPdu7I6cSWW+lA8mWTwK1Eym0FBl6d8i9q4GrxxcRTv2Q== -----END RSA PRIVATE KEY-----
自己署名デジタル証明書(検証用)「server.crt」の中身はこんな感じです。
-----BEGIN CERTIFICATE----- MIIDpDCCAowCCQDYJxgXlQ+UtjANBgkqhkiG9w0BAQsFADCBkzELMAkGA1UEBhMC SlAxDjAMBgNVBAgMBVRva3lvMQ4wDAYDVQQHDAVUYWl0bzEcMBoGA1UECgwTdGF0 c3VubyBqb2hvIHN5c3RlbTEbMBkGA1UEAwwSYmFpLnF1aXpnZW5kZXYubmV0MSkw ...省略... wpGlYCfAynDVPdE87rI5mitvPFfTAGn+M+kYTaVW4HqVvDMLX+X/3ID0aM5i+k3V 8e2s/GvubOtcYty1nLf4IMtz6ikrfDfiHEmu2nqb+wrsKyvuTwVLakgdKKRYZgQv EIoWUaXAfGDGYyOOsrN6XWwpqp0Yzh51+v1nK+PDBd/fIufge6BDA5EDH3wAJjXu PeTR5HfZoXN5bdBk4KC4ueAGdw8ogbQJ -----END CERTIFICATE-----
Salesforce接続アプリケーションを作成する
作業手順1.Salesforceにログインしたら、右上のメニューから「設定」画面を開きます。
作業手順2.設定画面の左側にあるメニューから「アプリケーションマネージャ」を開き、「新規接続アプリケーション」をクリックします。
作業手順3.接続アプリケーションを設定します。(設定完了後は「保存」を忘れないように)
- 接続アプリケーション名(任意の内容)
- API 参照名(分かりやすい説明を入れましょう)
- 取引先責任者 メール
- OAuth 設定の有効化(必ずチェックを入れてください)
- コールバック URL(利用しませんが、必須入力項目ですから、適当に何かを入力します。)
- デジタル署名を使用(必ずチェックを入れてください)
- 自己署名デジタル証明書(最初の手順で作った「server.crt」を選んでください)
- 選択した OAuth 範囲
※「フルアクセス (full)」だとアクセストークはうまく取れませんでした。- Web 経由のデータへのアクセスを提供 (web)
- データへのアクセスと管理 (api)
- ユーザに代わっていつでも要求を実行 (refresh_token, offline_access)
上記以外の設定内容はデフォルトのままで問題ございません。
作業手順4.「manage」ボタンを押して、管理画面を開きます。(ここはなぜか英語表記になっています。)
作業手順5.「ポリシーを編集」ボタンを押して、ポリシー編集画面を開きます。
作業手順6.「OAuth ポリシー」を次のように設定します。その他の設定はデフォルトのままで問題ございません。設定が終わったら「保存」ボタンを忘れずに押してください。
「OAuth ポリシー」を「管理者が承認したユーザは事前承認済み」に設定したら、アプリケーションの管理画面では「プロファイル」が設定可能になります。
作業手順7.アプリケーションの管理画面にある「プロファイル」設定エリアで「プロフィールを管理する」ボタンを押して、アプリケーションのプロフィールを割当てます。
REST API経由でSaleforceからデータ取得・更新したいので、ここはフル権限を持った「System Admin」を割当てました。
必要に応じて、適切なプロフィールを割当てましょう。
プロフィールの設定内容を保存したら、自動的にアプリケーションの管理画面に戻り、設定結果が確認できます。
PHPでJWTを作成する
SaleForceの開発者ガイドで公開した作成方法はこちらです。
※ドキュメントが古いか、翻訳ミスかはわかりませんが、誤ったところが多くて参考になれませんでした。
JWT(JSON Web Token)構造は大きく分けて、3つの部分になりまして、それぞれ「.」で区切られます。
- ヘッダー(Header)
- ペイロード(Payload)
- 署名(Sinature)
JWT(JSON Web Token)の文字列の全体を見ると、次のようになります。
{ヘッダー>}.{ペイロード}.{署名}
次のように、PHPでSaleForce用のOAuth 2.0 JWTが作成できます。
ここでopenssl_pkey_get_private関数に渡すファイルのパスにハマってしまいました。
ファイルパスは必ず「file://相対パス、または絶対パス」のように書いてください。
function base64UrlEncode($data) { return str_replace('=', '', strtr(base64_encode($data), '+/', '-_')); } $header = base64UrlEncode(json_encode([ 'alg' => 'RS256', ])); /** * audについて * 本番: https://login.salesforce.com * Sandbox: https://test.login.salesforce.com * スクラッチ組織: https://test.saleforce.com */ $payload = base64UrlEncode(json_encode([ //iss間違ったらエラーメッセージ「接続アプリケーションは存在しない」が返ってきます。 'iss' => '前の手順で作成したSaleForce接続アプリケーションのコンシューマ鍵', 'aud' => 'https://test.salesforce.com', //sub間違ったらエラーメッセージ「無効なユーザ」が返ってきます。 'sub' => 'SaleForceユーザのログインID', //ここの期限切れ時間はかなり適当です。exp間違ったらエラーメッセージ「トークが期限切れ」が返ってきます。 'exp' => time() + 3 * 60, ])); /** * 署名について * 前の手順で作成した「server.key」を利用してJWTのヘッダーとペイロードを書名します。 */ $signature = null; $privateKey = openssl_pkey_get_private('file://server.key'); openssl_sign($header . '.' . $payload, $signature, $privateKey, OPENSSL_ALGO_SHA256); openssl_free_key($privateKey); $signature = base64UrlEncode($signature); $jwt = $header . '.' . $payload . '.' . $signature;
PHPでアクセストークンを取得する(cUrl利用)
次のように、PHPでSaleForce側にアクセスして、アクセストークを発行して頂きます。
$post = [ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt, //前の手順で作ったJWTの文字列 ]; /** * アクセストークンを取得するAPIについて * 本番: https://login.salesforce.com/services/oauth2/token * Sandbox: https://test.login.salesforce.com/services/oauth2/token * スクラッチ組織: https://test.saleforce.com/services/oauth2/token */ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://test.salesforce.com/services/oauth2/token'); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 7); curl_setopt($ch, CURLOPT_TIMEOUT, 7); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); if($httpcode == 200) { $json = json_decode($response, true); if(isset($json['access_token'])) { $access_token = $json['access_token']; //do something. } } else { var_dump($httpcode); var_dump($response); } curl_close($ch);
問合せ結果として、次のようなjsonデータが返ってきます。
{ "access_token" => "***********************************", "scope" => "web id api", "instance_url" => "https://SaleForce環境名.salesforce.com", "id" => "https://test.salesforce.com/id/*****/*****", "token_type" => "Bearer" }
PHPでSaleForceから情報を取得する
SaleForceの開発者ガイドで公開したデータの問合せ方法の1つ:REST API/Query
PHPでのデータ問合せ方法(cUrl利用):
$query = "SELECT フィールド名 FROM テーブル名"; $query = http_build_query(['q' => $query]); $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: Bearer ' . $access_token, //前の手順で取得したアクセストークン(文字列) ]); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($ch, CURLOPT_URL, 'https://SaleForce環境名.salesforce.com/services/data/v20.0/query/?' . $query); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 7); curl_setopt($ch, CURLOPT_TIMEOUT, 7); //お問い合わせ $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); $json = json_decode($response, true); curl_close($ch);
まとめ
今回の記事では、SaleForceからデータを取得できるまでの手順をご紹介いたしました。
learningBOXもSaleForceと連携可能ですので、ぜひお試しください。