フロントエンド実装
この章では、サンプル・コードを使用して、加盟店アプリのフロントエンドの実装方法について説明します。
Note
サンプル・コードに目を通し、実装してから、次に進んでください。
次の図に、フロントエンド用の主なファイルを示します。これらは/final
プロジェクトの/resource
ディレクトリにあります。必要に応じディレクトリ構想を確認してください。3ds-web-adapter.js
は3DS-web-adapterです。
処理 1: 認証の初期化
認証を初期化するためには、フロントエンドが以下のように動作する必要があります。
- 3DSリクエスターに
認証の初期化
する為のメッセージを送信する(ステップ.1、およびステップ.2)。 - 応答メッセージを受信し、コールバック用の
iframe
をセットアップする(ステップ.5、およびステップ.6)。
ユーザーが決済ページの"Continue to checkout"ボタンをクリックすると、ブラウザーは、認証処理を開始するための情報を3DS-web-adapterに送信します(ステップ.1)。この処理はcheckout.html
のcheckout()
関数で実行されます。
1 2 3 4 5 6 7 8 9 10 | //checkout.html function checkout() { ... $("#cardholderInfoCard").remove(); $("#checkoutCard").removeClass("d-none"); //デモ用に結果画面を表示するため2秒後に移動する setTimeout(function () { window.location.href = "/auth/result"}, 2000); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
3ds-web-adapter.js
でthreeDSAuth()
関数が実行されます(ステップ.2)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //3ds-web-adapter.js function threeDSAuth(transId, cardHolderInfo, purchaseInfo) { console.log('init authentication'); $.ajax({ url: '/auth/init', type: 'POST', contentType: "application/json", data: JSON.stringify({ threeDSRequestorTransID: transId, cardExpiryDate: purchaseInfo.expiryDate, purchaseAmount: purchaseInfo.purchaseAmount, purchaseCurrency: purchaseInfo.purchaseCurrency, acctNumber: purchaseInfo.acctNumber, cardHolderInfo: cardHolderInfo // ここで他の情報を3DSリクエスターに送ることもできる。acctInfo等 }), success: function (data) { console.log('init auth returns:', data); $('<iframe id="threeds-container" width="0" height="0" style="visibility: hidden;" src="' + data.threeDSServerCallbackUrl + '"></iframe>') .appendTo('.challengeContainer'); }, error: function () { alert('error'); }, dataType: 'json' }); } |
threeDSAuth()
関数は3DSリクエスターのURL /auth/init
にPOSTリクエストを行います(行6)。オブジェクトはJSON形式でPOSTされます。3DSリクエスターがこのリクエストを処理しているかの確認については、ここを参照してください。
Note
各自の実装方法によってthreeDSAuth()
を変更し、cardholderInfo
、purchaseInfo
、transId
でなく独自のオブジェクトを転送できます。データ構造については、API documentを参照してください。
/auth/init
からの応答が正常に得られると(ステップ.5)、3ds-web-adapter.js
は非表示のiframe
を決済ページに埋め込み(ステップ.6)、ACSと3DSサーバーがthreeDSServerCallbackUrl
を使用してブラウザー情報を収集できるようになります(ステップ.7)(行20〜23)。
処理 2: 認証の実行
認証を実行するためには、フロントエンドが以下のように動作をする必要があります。
notify_3ds_events.html
を実行する。- 3DSリクエスターに
認証の実行
メッセージを送信する(ステップ.8、およびステップ.9)。 - 認証結果をフリクションレス・フローまたはチャレンジ・フローとして処理する(ステップ.13、ステップ.14(F)、またはステップ.14(C))。
notify_3ds_events.html
は、認証処理を開始するために使用されます(ステップ.8)。3DSリクエスターは、このファイルに対し、transId
、callbackType
、およびオプションのparam
を返します。バックエンドでの実行については、ここを参照してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <!--notify_3ds_events.html--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>3DSecure 2.0 Authentication</title> </head> <body> <form> <input type="hidden" id="notifyCallback" name="notifyCallback" data-th-value="${callbackName}"/> <input type="hidden" id="transId" name="transId" data-th-value="${transId}"/> <input type="hidden" id="param" name="param" data-th-value="${callbackParam}"/> </form> <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> <script> //チェックアウトページのiframe内で実行される。 var callbackFn = parent[$('#notifyCallback').val()]; //callbackFnは3DSリクエスターの3ds-notifyハンドラーメソッドから渡されます if (typeof callbackFn === 'function') { callbackFn($('#transId').val(),$('#param').val()); } </script> </body> </html> |
callbackName
により、3ds-web-adapter.js
で呼び出されるメソッドが異なることが分かります(ステップ.8)。callbackName
の値は_onThreeDSMethodFinished
または_onThreeDSMethodSkipped
のいずれかでなければなりません。 各メソッドについて以下に説明します。
_onThreeDSMethodFinished
- 3DSメソッドが完了したことを通知し、ブラウザー情報の収集が完了したことを示す_doAuth()
を呼び出します。_onThreeDSMethodSkipped
- 3DSメソッドをスキップしたことを通知し、ACSによるブラウザー情報の収集をスキップしたことを示す_doAuth()
を呼び出します。
3ds-web-adapter
の_doAuth()
は、/auth
へのPOSTリクエストを行い認証を実行します(ステップ.9)。3DSリクエスターがこのリクエストを処理しているかの確認については、ここを参照してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //3ds-web-adapter.js function _doAuth(transId) { ... $.post("/auth", {id: transId}).done(function (data) { console.log('auth returns:', data); if (!data) { alert('error'); return; } switch (data.transStatus) { case "Y": authSuccess(data, transId); break; case "C": startChallenge(data.challengeUrl); break; ... } } |
_doAuth()
は/auth
へリクエストをPOSTし(行4)、結果のdata
を取得します。この後に実行されるフローは、返されたtransStatus
により異なります(行14と17)。
transStatus
がY
の場合は認証に成功したことを意味します。3DS-web-adapterはフリクションレス・フローに切り替わり、次の処理であるauthSuccess()
関数を実行します(ステップ.14(F))。-> 認証結果の取得。
transStatus
がC
の場合、3ds-web-adapter.js
はstartChallenge()
を呼び出し、チャレンジ画面を表示するためsrc
属性がchallengeUrl
にセットされたiframe
をに挿入します(ステップ.14(C))。
1 2 3 4 5 6 7 8 9 | function startChallenge(url) { //remove the spinner $(".spinner").remove(); //create the iframe $('<iframe src="'+url+'" class="h-100 w-100 border-0" id="challengeWindow" name="challengeWindow"></iframe>') .appendTo('.challengeContainer'); } |
Note
チャレンジシナリオをテストしたい場合は、20個のパイナップルをカートに追加するなど、$100以上の商品の購入操作を試みてください。
iframe
クラスがh-100
およびw-100
にセットされたことが分かります。これらはそれぞれ、height: 100%!important
およびwidth: 100%!important
というcss型を実装するためのブートストラップ・デフォルト・クラスです。これが必要なのは、ACSから与えられた内容に応じてiframe
のサイズを調整しなければならないためです。チャレンジ画面は次のスクリーンショットのようになるはずです。
Info
実際の状況でACSが実行するのは、購入金額の確認だけで済むような簡単な処理ではなく、取得したカード会員情報に応じたリスクに基づく複雑な認証処理になります。同様に、認証メソッドはイシュアーにより決定され実行されます。
処理 3: 認証結果の取得
認証結果を取得するためには、フロントエンドが以下のように動作する必要があります。
- 3DSリクエスターに
認証結果の取得
の為のメッセージを送信する(ステップ.15(F)、またはステップ.20(C))。 - 結果を画面に表示する(ステップ.17(F)、またはステップ.22(C))。
認証結果が用意できると、3DSリクエスターはnotify_3ds_events.html
の_onAuthResult
を使用してフロントエンドに通知します。次に、3ds-web-adapterは次の図のURL /auth/result
を使用して認証結果の取得
リクエストを3DSリクエスターに送信します。3DSリクエスターがnotify_3ds_events.html
メッセージを処理しているかの確認については、ここを参照してください。
1 2 3 | function _onAuthResultReady(transId) { //redirect to result page window.location.href = "/auth/result?txid=" + transId; |
result.html
ページにリダイレクトします。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <div class="col-sm-8"> <div class="card"> <div class="card-header">Transaction successful</div> <div class="card-body"> <h4 class="card-title text-success">3D secure authentication was successful</h4> <p class="card-text">You may move onto authorization using the result below or you can press "Back To Home" to restart authentication process.</p> <dl class="row"> <dt class="col-sm-3">Trans Status</dt> <dd class="col-sm-9" data-th-text="${result.transStatus}">Y</dd> <dt class="col-sm-3">ECI</dt> <dd class="col-sm-9" data-th-text="${result.eci}">eci value</dd> <dt class="col-sm-3">CAVV</dt> <dd class="col-sm-9" data-th-text="${result.authenticationValue}">cavv value</dd> <dt class="col-sm-3">Other Info</dt> <dd class="col-sm-9"></dd> </dl> <a href="/" class="btn btn-primary">Back To Home</a> </div> </div> </div> |
Success
お疲れ様でした。これでフロントエンドの導入は完了です。通常、この処理の後は、取引を完了するための、取引ステータス、ECI、CAVVを使用してオーソリの実行に進みます。
次のチャプター
nextボタンを選択し、3DSリクエスター用のバックエンド導入についてご覧ください。