3DSリクエスターセットアップガイド¶
3DSリクエスター は加盟店側の3DS2コンポーネントであり、購入者のデバイスから3DSサーバーに3Dセキュアデータを渡すために使用されます。 決済認証における3DSリクエスターは通常、既存の加盟店のオンラインショッピング用ウェブサーバーです。
3DSリクエスターは、3DSリクエスターアプリまたは購入者のデバイス/ブラウザに3DSメソッドを介してカード会員につながります。ブラウザべース のトランザクションを3Dセキュア処理するには、3DSメソッドを使用してブラウザ情報/デバイス詳細情報を収集し、チャレンジが必要な場合、ACS(アクセス・コントロール・サーバー)はカード会員にUIを表示するためのHTMLをブラウザに提供します。
この項では、ActiveServerに接続するためのGPaymentsのサンプルコードを使用し、3DSリクエスターコードを加盟店ウェブサーバーに組み込む概要を説明します。加盟店アプリの組み込みに関する詳細は、ActiveSDKの文書を参照してください。
前提条件¶
本書の利用に際して想定されている前提条件を、以下に示します。
- Javaの基本事項を理解していること
- ウェブテクノロジーの基本事項を理解していること(HTML、CSS、Javascript)
- JDKがインストールされていること。
- 任意のIDE。
- Apache Mavenがインストールされていること(https://maven.apache.org/install.html)。
- GPaymentsのサンプルコードパッケージをここからダウンロードしてあること
はじめに¶
3DS2フローの組み込みに使用するサンプルの加盟店決済サイトは、Springboot プロジェクトを使用して作成されています。参考までに、HTMLページの作成に使用したものを以下に示します。
サンプルの加盟店決済ページには以下の 3つ の主要ページが含まれています。
index.html
- 購入する商品を選択するショッピングサイト。checkout.html
- カード会員情報と処理画面が含まれた決済ページ。result.html
-トランザクションが成功したか失敗したかを表示するトランザクション結果ページ。
サンプルコード実行方法¶
上記のGPaymentsサンプルコードパッケージには次の2つのフォルダーが含まれています
- sampleCode - サンプルの加盟店決済ページ (3DS2認証フローは含まれていません)。
- finalCode - 3DS認証フローが組み込まれた 最終的な加盟店決済ページ。本書の順を追った説明に従って操作を進め、最後に得られるのがこの最終コードです。
サンプルの加盟店サイトを実行する手順を、以下に示します。
-
3DSリクエスターと3DSサーバーが相互認証を行えるよう、GPaymentsからユーザーに提供されるクライアント証明書(.p12ファイル)を
/finalCode/src/main/resources/certs
というファイルパスにコピーします。証明書ファイルを受け取っていない場合は、GPaymentsにお問い合わせください。 -
ターミナル(Linux)または コマンドプロンプト(Windows)を開き、実行するパッケージに応じてプロジェクトのルートディレクトリ
/sampleCode
または/finalCode
に移動します。 -
ルートディレクトリで次のコマンド行を実行します。初めて実行する際にはMavenが必要な依存関係をダウンロードするため、2、3分かかることがあります。
1 | mvn spring-boot:run |
ポイント
上記のコマンドを実行する前に必ず、Mavenがインストールされ使用可能な状態になっていなければなりません。Mavenのインストールについては、https://maven.apache.org/install.htmlを参照してください。
注意
Windowsの場合は、WindowsファイアウォールがJavaのネットワークアクセスに関するセキュリティアラートを表示することがありますが、アクセスを許可して先に進んでください。
http://localhost:8082にアクセスするとサンプルのカートページを表示できます。カートにいくつかの商品を追加し、デフォルトのカード会員情報を使用して決済してみてください。
ポイント
ポート8082が使用中の場合はエラーが表示される可能性があります。その場合は、/resources/application.properties
ファイルに次の行を追加してポートを設定してください。
1 | server.port = # 使用したいポート番号 |
注意
デモ専用のサンプルのリクエスターコードはHTTPで実行されています。
3DS2の処理フロー¶
3DS2には次の2つの主要な認証フローがあります。
- フリクションレスフロー - フリクションレスフローでは、認証 (AReq/ARes) メッセージを含む3Dセキュア認証フローが開始されます。このフローでは、リスクベースの認証を使用して、認証を成功させるためにカード会員による追加の操作が必要か否かを判断します。
- チャレンジフロー - ACSが「認証を完了するためにはカード会員による追加の情報が必要である」と判断した場合は、フリクションレスフローからチャレンジフローに切り換わります(リスクが特定の限界値より大きい場合や法的に要求されている場合など)。チャレンジフローでは、フリクションレスフローに含まれる AReq、ARes メッセージの他に、チャレンジ (CReq/CRes) メッセージと結果 (RReq/RRes) メッセージが含まれます。
点線は、3DS2の範囲外であるオーソリのプロセスを示します。
認証ステップ¶
これらの認証フローに基づき、ActiveServerによる ブラウザベース 認証を実行するには、次のような3つのステップがあります。
-
認証の開始
/api/v1/auth/brw/init/{messageCategory}
を呼び出します。/brw/init/{messageCategory}
には、3DSサーバーが認証要求(AReq)を生成するのに必要な(3DSリクエスターからの)すべての情報が含まれています。
-
認証の実行
/api/v1/auth/brw
を呼び出します。/brw
は、3DSメソッドとデバイスの情報収集が完了したときに3DSリクエスターが呼び出しを行うために使用されます。
-
認証結果の取得
/api/v1/auth/brw/result
を呼び出します。/brw/result
は、認証結果(AResまたはRResチャレンジのステータスに応じ)に含まれる情報を3DSリクエスターに応答します。
シーケンス図¶
次のシーケンス図は、GPayments APIとサンプルコードを使用した3DS2フローにおける 3DSリクエスター の機能に焦点を当て、3DS2認証処理をステップごとに分解して示したものです。
-
認証を開始するための情報を送信
- 3DS2認証を行えるよう、カード会員から収集した情報を使用して、3ds-web-adapter.js内で定義されている
threeDSAuth()
関数を呼び出します。
- 3DS2認証を行えるよう、カード会員から収集した情報を使用して、3ds-web-adapter.js内で定義されている
-
認証の開始
threeDSAuth()
は、決済ページから収集した情報を使用して3DSリクエスターにPOST要求を行い、認証を開始するように3DSリクエスターに要求します。
-
認証の開始 (
/brw/init/{messageCategory}
)- 3DSリクエスターは、認証を開始するため、
/brw/init/{messageCategory}
へのPOST API呼び出しを行います。
- 3DSリクエスターは、認証を開始するため、
-
threeDSServerCallbackUrl
を応答/brw/init/{messageCategory}
からの成功応答には、threeDSServerCallbackUrl
とthreeDSServerTransID
が含まれています.
-
threeDSServerCallbackUrl
を応答- 3DSリクエスターは
3ds-web-adapter
にこの情報を返します。
- 3DSリクエスターは
-
コールバック
iframe
を設置src
がthreeDSServerCallbackUrl
に設定された非表示のiframe
を挿入します。これにより、3DSサーバーが3DSリクエスターに接続可能になります。3DSサーバーは、このiframe
へのコールバックを行います。
-
ブラウザ情報の収集とACS 3DSメソッドの実行
- ACSは3DSメソッドURLを使用してブラウザに接続し、ブラウザ情報を収集します(3DSサーバーにより実現)。
-
コールバック関数の呼び出し
- 3DSメソッドが完了した場合またはスキップされた場合にACSが3DSリクエスターに通知できるよう、認証開始時に3DSリクエスターは
eventCallBackUrl
を送ります。 - 3DSリクエスターは、通知を受け取るとブラウザに通知し、
notify-3ds-events.html
を開きcallbackFn
を呼び出します。
- 3DSメソッドが完了した場合またはスキップされた場合にACSが3DSリクエスターに通知できるよう、認証開始時に3DSリクエスターは
-
認証の実行
callbackFn
は_on3DSMethodSkipped()
または_on3DSMethodFinished()
のいずれかであり、最終的にはいずれもdoAuth()
を呼び出し、doAuth()
は3DSリクエスターに認証を実行するように指示します。
-
認証の実行 (
/brw
)- 3DSリクエスターは
/brw
への呼び出しを行い、/brwは認証処理を開始します。
- 3DSリクエスターは
-
AReq/ARes
- 認証要求は、ディレクトリサーバーを介して3DSサーバーからACSに送られます。認証応答と結果は、ACSから3DSサーバーに送られます。
-
認証結果を応答
/brw
は、3DSリクエスターへの戻り値としてtranStatus
を返します。
-
認証結果を応答
- 認証結果をウェブアダプターに返します。
解説
返されたtransStatus
が「Y」の場合はステップ14(F)
に、「C」の場合はステップ14(C)
に進んでください。
フリクションレスフローの場合¶
14(F). 結果の表示(フリクションレスの場合)
- 認証結果として得られた
transStatu
sが「Y」の場合はauthSuccess()
が呼び出され、authSuccess()
はページを/auth/result?transId
にリダイレクトします。
15(F). 認証結果を要求 (認証結果を表示するページが必要な場合)
- ブラウザは3DSリクエスターに
transID
を通知し、トランザクションの結果を要求可能な状態になります。
16(F). 認証結果を要求(/brw/result
)
- 3DSリクエスターは
/brw/result
を呼び出し、3DSサーバーから認証結果の要求します。
17(F). ブラウザに結果を表示
- 結果ページに認証結果が表示されます。
チャレンジフローの場合¶
14(C). iframe
の設置(チャレンジの場合)。
- 認証結果として得られた
transStatus
が「C」にセットされている場合はstartChallenge()
が呼び出され、startChallenge()
はチャレンジ用のiframe
を挿入します。
15(C). HTMLの交換
- ACSはチャレンジ画面を
iframe
に埋め込み、カード会員は認証チャレンジを行います。
16(C). チャレンジ結果の判定
- ACSは、実行されたチャレンジの合否を判定します。
17(C). RReq/Res
- ACSはディレクトリサーバーを介して3DSサーバーに、認証結果を含む結果要求を送ります。要求を受け取った3DSサーバーは結果応答を返します。
18(C). チャレンジ応答(最終的なCRes)
- ACSは3DSリクエスターに、最終的なチャレンジ応答を送ります。
19(C). 3DSチャレンジを終了して結果画面を表示
- チャレンジが終了したため、3DSリクエスターはページを
/auth/result?transId
にリダイレクトします。
20(C). 認証結果を要求(認証結果を表示するページが必要な場合)
- ブラウザは3DSリクエスターに
transId
を通知し、トランザクションの結果を要求に使用可能な状態になります。
21(C). 認証結果を要求(/brw/result
)
- ステップ16aと同様に、3DSリクエスターは
/brw/result
からの結果の受け取りを要求します。
22(C). ブラウザに結果を表示
- ブラウザの結果画面に認証結果が表示されます。
3DSリクエスター実装ガイド¶
この項では、前提条件の項でダウンロードした簡単なショッピングサイトプロジェクトに3DS2フローを組み込めるように、上記のステップを実装する方法を説明します。この項の説明は、既存の決済処理に同じ機能を追加する場合にも適用できます。
このチュートリアルではIntellij IDEAを使用しています。
完成したコードについてさらに詳しく知りたい場合は、3DS2が組み込まれた最終的な加盟店決済ページを確認してください(GPaymentsサンプルコードパッケージの/finalCode
フォルダーにあります)。3DSリクエスターのデモコードの概要については、最終的なデモコードの項を参照してください。
解説
本書の目的は、Javaを使用して3DSリクエスターを実装するための一般的なフローを理解していただくことにあります。一般的なフローを理解して頂くことにより、異なるプログラミング言語で開発されている可能性のある加盟店の決済ページに3DSリクエスターを組み込めるようにいたします。
ステップ1:認証の開始¶
まず、認証を開始する(すなわち/brw/init/{messageCategory}
を呼び出す)手順について説明します。
messageCategory
はpa
またはnpa
のいずれかであり、それぞれ、決済認証または非決済認証を意味します。
ヒント
各APIのエンドポイントは認証APIの文書の参照先にリンクされており、APIの使用方法に関する詳細情報にアクセスできます。
GPaymentsサンプルコードパッケージには/sampleCode
というフォルダーがあります。読者のIDEで [ファイル]>[開く]>[参照] とクリックし、sampleCode
フォルダーを指定して [OK] をクリックし、このディレクトリを開きます。
また、認証機能の実装に役立つ3ds-web-adapter.js
も用意されています。
解凍したfinalCode
プロジェクトから3ds-web-adapter.js
をコピーし、sampleCode
プロジェクトの/resources/static/jsディレクトリに貼り付けます。必要に応じjs
ディレクトリを作成してください。このファイルの場所が分からない場合は、最終的なコードのディレクトリツリーを確認してください。
後述の強調表示になっている行を 追加 して3ds-web-adapter.js
ファイルをcheckout.html
ページにインポートします。
1 2 3 4 5 6 7 8 9 10 11 12 | .... <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script> <script src="/js/3ds-web-adapter.js"></script> ..... |
アダプターを使用するようにcheckout.html
を編集します。checkout.html
のcheckout()
関数を見てください。次に示すコードのようになっているはずです。この関数は、JQueryを使用してHTML文書からカード会員入力フィールドの値を取得し、新しい変数transId
、cardHolderInfo
、およびpurchaseInfo
を初期化します。
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 34 35 36 37 38 39 40 41 42 | //checkout.html function checkout() { var transId = $('#transId').val(); // NOTE: Some attributes are set to default values for demo purpose var cardHolderInfo = { billAddrLine1: $('#billAddrLine1').val(), billAddrLine2: $('#billAddrLine2').val(), billAddrLine3: 'abc Line 3', billAddrCity: $('#billAddrCity').val(), billAddrState: $('#billAddrState').val(), billAddrPostCode: $('#billAddrPostCode').val(), billAddrCountry: '036', shipAddrLine1: $('#shipAddrLine1').val(), shipAddrLine2: $('#shipAddrLine2').val(), shipAddrLine3: 'abc Line 3', shipAddrCity: $('#shipAddrCity').val(), shipAddrState: $('#shipAddrState').val(), shipAddrPostCode: $('#shipAddrPostCode').val(), shipAddrCountry: '036', mobilePhone: {cc: '61', subscriber: $('#phoneNumber').val()}, homePhone: {cc: '61', subscriber: '90123917131'}, workPhone: {cc: '61', subscriber: '89102183192'}, email: $('#email').val(), cardholderName: $('#cardholderName').val() }; var purchaseInfo = { acctNumber: $('#cardNumber').val(), purchaseAmount: '100', purchaseCurrency: '840', //USD expiryDate: $('#cardExpiry').val() }; //remove cardholder information class, checkout button and show spinner effect $("#checkoutButton").remove(); $("#cardholderInfoCard").remove(); $("#checkoutCard").removeClass("d-none"); setTimeout(function () { window.location.href = "/auth/result"}, 2000); } |
checkout()
の中の強調表示になっている行をcheckout.html
に追加し、threeDSAuth()
関数を呼び出します(ステップ1)。これで認証処理が開始されます。
1 2 3 4 5 6 7 8 9 | function checkout() { ... $("#cardholderInfoCard").remove(); $("#checkoutCard").removeClass("d-none"); //move to result screen 2 seconds after setTimeout(function () { window.location.href = "/auth/result"}, 2000); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
1 2 3 4 5 6 7 8 | function checkout() { ... $("#cardholderInfoCard").remove(); $("#checkoutCard").removeClass("d-none"); //setTimeout(function () { window.location.href = "/auth/result"}, 2000); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
ポイント
次に示すコードは、3ds-web-adapter.js
で定義されているthreeDSAuth()
関数です。threeDSAuth()
はページからオブジェクトをJSONフォーマットで/auth/init
(6行目)に送信しています。たとえば、threeDSRequestorTransID
がページからの値transId
に初期化されています。
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 // you can pass on more information if you need to e.g. 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()
は必要に応じ変更でき、cardholderInfo
、purchaseInfo
、transId
の代わりに既存の加盟店決済ページから必要とするオブジェクトを送ることができます。転送可能なデータエレメントの型は、最終的なコードの/dto/activeserver
ディレクトリにあるInitAuthRequestBRW
に示されています。また、APIの文書でも確認できます。
3ds-web-adapter.js
は/auth/init
にPOST要求を行います(ステップ2)。したがって、この要求を処理するための新しいコントローラークラスが必要です。
/java/sample_requestorディレクトリに新しいコントローラークラスAuthController.java
を作成します。
次に示すコードをAuthController.java
内に 追加 します。このコードには/auth/init
要求に対応するハンドラ関数initAuth()
が含まれています。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.gpayments.requestor.sample_requestor; import com.gpayments.requestor.sample_requestor.dto.activeserver.*; import com.gpayments.requestor.sample_requestor.transaction.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @RestController @RequestMapping("/") public class AuthController { private static final Logger logger = LoggerFactory.getLogger(AuthController.class); // RestTemplate class for making API request private final RestTemplate restTemplate; private final TransactionManager transMgr; // ActiveServer entry points for authentication public static final String THREE_DS_SERVER_URL = "THREE_DS_SERVER_URL"; private final String THREE_DS_REQUESTOR_URL = "THREE_DS_REQUESTOR_URL"; @Autowired public AuthController(RestTemplate restTemplate, TransactionManager transMgr) { this.restTemplate = restTemplate; this.transMgr = transMgr; } /** * Handler method for /auth/init, it initialises authentication through /brw/init/{} * * @param request * @return */ @PostMapping("/auth/init") public InitAuthResponseBRW initAuth(@RequestBody InitAuthRequestBRW request) { // find transaction with transaction id MerchantTransaction transactionInfo = transMgr.findTransaction(request.getThreeDSRequestorTransID()); // fill the request with default data fillInitAuthRequestBRW(request, THREE_DS_REQUESTOR_URL + "/3ds-notify"); logger.info("initAuthRequest {}", request); String initBrwUrl = THREE_DS_SERVER_URL + "/brw/init/{messageCategory}"; // Initialise authentication by making POST request to /brw/init/{messageCategory} (Step. 3) InitAuthResponseBRW initAuthResponseBRW = restTemplate.postForObject(initBrwUrl, request, InitAuthResponseBRW.class); logger.info("initAuthResponseBRW {}", initAuthResponseBRW); // set InitAuthResponseBRW for future use transactionInfo.setInitAuthResponseBRW(initAuthResponseBRW); return initAuthResponseBRW; } } |
{messageCategory}
をpa
に、非決済認証を開始する場合は{messageCategory}
をnpa
に 置換 します。下の例ではpa
を使用しています。
1 2 3 4 5 6 7 | //AuthController.java String initBrwUrl = THREE_DS_SERVER_URL + "/brw/init/pa"; // Initialise authentication by making POST request to /brw/init/{messageCategory} (Step. 3) InitAuthResponseBRW initAuthResponseBRW = restTemplate.postForObject(initBrwUrl, request, InitAuthResponseBRW.class); .... |
THREE_DS_SERVER_URL
を、デフォルト設定で提供されているURLに 置換 します。本番環境の場合はユーザー自身の3DSサーバーのURLになります。
1 2 3 | //AuthController.java private final String THREE_DS_SERVER_URL = "https://uat.testlab.activeserver.cloud/api/v1/auth"; .... |
THREE_DS_REQUESTOR_URL
を、デフォルト設定で提供されているURLに置換するか、ユーザー自身がホストする3DSリクエスターのURLに変更します。
1 2 3 | //AuthController.java private final String THREE_DS_REQUESTOR_URL = "http://localhost:8082"; .... |
activeserver
フォルダーを コピー して、/java/sample_requestor/dto
ディレクトリに貼り付けます。このフォルダーには、API呼び出しを行うのに必要なすべてのクラスが含まれています。認証を開始する上で最も重要なのが、以下のクラスです。
-
InitAuthRequestBRW
- InitAuthRequestBRW -/brw/init/{messageCategory}
へのAPI呼び出しを行うのに必要なすべてのデータを保持しています(ステップ3)。 -
InitAuthResponseBRW
-/brw/init/{messageCategory}
のAPI呼び出しへの応答に関する情報を保持しています(ステップ4)。
AuthController.java
に以下の関数を 追加 します。この関数は、InitAuthRequestBRW
にデモ用のデフォルトデータをセットします。ただし本番環境の場合は、加盟店のデータベースからのデータ、またはcheckout.html
から送られたカード会員情報からのデータをロードするように、この関数を書き直してください。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | //AuthController.java /** * This method is to fill in the InitAuthRequestBRW with demo data, you need to fill the information from your database * @param initAuthRequestBRW * @param eventCallBackUrl */ private void fillInitAuthRequestBRW(InitAuthRequestBRW initAuthRequestBRW, String eventCallBackUrl) { initAuthRequestBRW.setAcctID("personal account"); // Fill AcctInfo with default data. AcctInfo acctInfo = new AcctInfo(); acctInfo.setChAccAgeInd("03"); acctInfo.setChAccChange("20160712"); acctInfo.setChAccChangeInd("04"); acctInfo.setChAccDate("20140328"); acctInfo.setChAccPwChange("20170328"); acctInfo.setChAccPwChangeInd("02"); acctInfo.setNbPurchaseAccount("11"); acctInfo.setPaymentAccAge("20160917"); acctInfo.setPaymentAccInd("02"); acctInfo.setProvisionAttemptsDay("3"); acctInfo.setShipAddressUsage("20160714"); acctInfo.setShipAddressUsageInd("02"); acctInfo.setShipNameIndicator("02"); acctInfo.setSuspiciousAccActivity("02"); acctInfo.setTxnActivityDay("1"); acctInfo.setTxnActivityYear("21"); initAuthRequestBRW.setAcctInfo(acctInfo); initAuthRequestBRW.setAcctType("03"); initAuthRequestBRW.setAuthenticationInd("01");//01 = Payment transaction // fills ThreeDSRequestorAuthenticationInfo ThreeDSRequestorAuthenticationInfo threeDSRequestorAuthenticationInfo = new ThreeDSRequestorAuthenticationInfo(); threeDSRequestorAuthenticationInfo.setThreeDSReqAuthData("login GP"); threeDSRequestorAuthenticationInfo.setThreeDSReqAuthMethod("02"); threeDSRequestorAuthenticationInfo.setThreeDSReqAuthTimestamp("201711071307"); initAuthRequestBRW.setAuthenticationInfo(threeDSRequestorAuthenticationInfo); // fills MerchantRiskIndicator, optional but strongly recommended for the accuracy of risk based authentication MerchantRiskIndicator merchantRiskIndicator = new MerchantRiskIndicator(); merchantRiskIndicator.setDeliveryEmailAddress("test@123.com"); merchantRiskIndicator.setDeliveryTimeframe("02"); merchantRiskIndicator.setGiftCardAmount("123"); merchantRiskIndicator.setGiftCardCount("02"); merchantRiskIndicator.setGiftCardCurr("840"); merchantRiskIndicator.setPreOrderDate("20170519"); merchantRiskIndicator.setPreOrderPurchaseInd("02"); merchantRiskIndicator.setReorderItemsInd("01"); merchantRiskIndicator.setShipIndicator("01"); initAuthRequestBRW.setMerchantRiskIndicator(merchantRiskIndicator); /** * Options for threeDSRequestorChallengeInd - Indicates whether a challenge is requested for this transaction. * Values accepted: * 01 = No preference * 02 = No challenge requested * 03 = Challenge requested: 3DS Requestor Preference * 04 = Challenge requested: Mandate * 05–79 = Reserved for EMVCo future use (values invalid until defined by EMVCo) * 80-99 = Reserved for DS use */ initAuthRequestBRW.setChallengeInd("01"); initAuthRequestBRW.setEventCallbackUrl(eventCallBackUrl); //Set this to your url initAuthRequestBRW.setMerchantID("123456789012345"); initAuthRequestBRW.setPurchaseDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); initAuthRequestBRW.setPurchaseInstalData("24"); initAuthRequestBRW.setRecurringExpiry("20180131"); initAuthRequestBRW.setRecurringFrequency("6"); initAuthRequestBRW.setTransType("03"); } |
MerchantTransaction.java
および対応するGetメソッドとSetメソッドに、新しい変数initAuthResponseBRW
を 追加 します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //MerchantTransaction.java import com.gpayments.requestor.sample_requestor.dto.activeserver.InitAuthResponseBRW; public class MerchantTransaction { private InitAuthResponseBRW initAuthResponseBRW; ... //getter public InitAuthResponseBRW getInitAuthResponseBRW() { return initAuthResponseBRW; } //setter public void setInitAuthResponseBRW(InitAuthResponseBRW initAuthResponseBRW) { this.initAuthResponseBRW = initAuthResponseBRW; } |
GPaymentsからユーザーに提供されるクライアント証明書(.p12ファイル)を コピー し、/resources/certsディレクトリに貼り付けます。/certs
ディレクトリがない場合は作成してください。証明書ファイルを受け取っていない場合は、GPaymentsにお問い合わせください。
最終的なコードの中にある証明書ファイルcacerts.jks
を コピー し、/resources/certsディレクトリに貼り付けます。証明書が必要な理由は、相互SSL認証を行うためにユーザーの3DSリクエスターと3DSサーバーの間の相互認証が必要だからです。
/java/sample_requestor/configディレクトリ内に構成クラスRestClientConfig.java
を作成します。config
ディレクトリがない場合は作成してください。
次に示すコードを コピー し、RestClientConfig.java
に貼り付けます。
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 34 35 36 37 | //RestClientConfig.java package com.gpayments.requestor.sample_requestor.config; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.ResourceUtils; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLContext; @Configuration public class RestClientConfig { private final String CERTIFICATE_PASSWORD = "CERTIFICATE_PASSWORD"; @Bean public RestTemplate restTemplate() throws Exception { SSLContext sslContext = SSLContextBuilder .create() .loadKeyMaterial(ResourceUtils.getURL("classpath:certs/client_certificate.p12"), CERTIFICATE_PASSWORD.toCharArray(), CERTIFICATE_PASSWORD.toCharArray()) .loadTrustMaterial(ResourceUtils.getURL("classpath:certs/cacerts.jks"), CERTIFICATE_PASSWORD.toCharArray()) .build(); CloseableHttpClient client = HttpClients.custom() .setSSLContext(sslContext) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(client); return new RestTemplate(httpRequestFactory); } } |
CERTIFICATE_PASSWORD
を、デフォルト設定で提供されるパスワードに 置換 します。本番環境では、ユーザーの証明書が含まれているキーストア用のパスワードになります。
1 2 | //RestClientConfig.java private String CERTIFICATE_PASSWORD = "123456"; |
解説
上記の方法はJava言語でのクライアント証明書を使用してユーザーの3DSリクエスターと3DSサーバーが相互認証する方法ですが、サーバ側のコードを別の言語で実装される場合には、類似の手順が必要です。
SSLContextBuilder
クラスに必要なApache HttpClientを取得するため、以下の依存関係をpom.xml
に 追加 します。
1 2 3 4 5 6 7 8 | <dependencies> ... <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> </dependencies> |
もう一度アプリを 実行 し、http://localhost:8082からアクセスして決済処理を行います。
/api/v1/auth/brw/init/{messageCategory}
に対し成功応答が得られ、Intellijのログをチェックすると下記のような有効なthreeDSServerCallbackUrl
を取得出来ているはずです。
1 2 3 4 5 6 7 8 9 | { "errorCode":"null", "errorComponent":"null", "errorDescription":"null", "errorDetail":"null", "errorMessageType":"null", "threeDSServerCallbackUrl":"https://uat-callback.testlab.activeserver.cloud/api/v1/auth/brw/callback?transId=ade87add-b50c-42da-bbea-cdcbd85dcbf3", "threeDSServerTransID":"ade87add-b50c-42da-bbea-cdcbd85dcbf3" } |
決済処理は3ds-notify
の段階で停止しますが、これは3ds-notify
がまだ実装されていないためであり、この実装方法については次の項で説明します。
ヒント
コード変更を確定するにはプロジェクトを再実行する必要があります。CTRL+C
を押して現在実行中のアプリを終了し、次に示すコマンド行を入力してプロジェクトを再実行します。
1 | mvn spring-boot:run |
3DSサーバーはコールバックURLをACSは3DSメソッドを使用して、リスクベース認証に必要なブラウザ情報を収集します。
ポイント
/auth/init
からの成功応答が得られた後(ステップ5) 、3ds-web-adapter.js
は非表示のiframe
を決済ページに挿入しますので(ステップ6) 、ACSと3DSサーバーはthreeDSServerCallbackUrl
を使用してブラウザ情報を収集できます(ステップ7))。
1 2 3 4 5 | //3ds-web-adapter.js success: function(data) { $('<iframe id="threeds-container" width="0" height="0" style="visibility: hidden;" src="'+ data.threeDSServerCallbackUrl+'"></iframe>') .appendTo('.challengeContainer'); }, |
ステップ2: 認証の実行¶
前のステップで、3ds-web-adapter.js
はthreeDSServerCallbackUrl
にセットされたコールバックsrc
を使用してiframe
を挿入しています。これにより、3DSサーバーはブラウザへのコールバックを行って(ステップ7)必要なブラウザ情報を収集できます。
また、eventCallBackUrl
をTHREE_DS_REQUESTOR_URL/3ds-notify
にセットして /brw/init/{messageCategory}
を呼び出しています(第2行)。このURLは3DSサーバーが3DSメソッドが完了またはスキップされた場合に3DSリクエスターに通知するエンドポイントになります。
1 2 3 | //AuthController.java fillInitAuthRequestBRW(request, THREE_DS_REQUESTOR_URL + "/3ds-notify"); ..... |
ですので、3DSサーバーからのAPIコールを受け取るハンドラ関数が必要になります。
次に示すコードをMainController.java
に 追加 します。このハンドラ関数はパラメーターtransId
、callbackType
を受け付けます。オプションパラメーターcallbackType
は3DSMethodFinished
または3DSMethodSkipped
のいずれかです。さらに、ハンドラ関数は、String型notify_3ds_events
を返します。Springbootに詳しくない方のために参考としてですが、これは/resources/templatesディレクトリから名前が一致するHTMLページを返すことを意味します。
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 | // MainController.java @PostMapping("/3ds-notify") public String notifyResult( @RequestParam("requestorTransId") String transId, @RequestParam("event") String callbackType, @RequestParam(name = "param", required = false) String param, Model model) { String callbackName; // check the callbackType and initialise callbackName if ("3DSMethodFinished".equals(callbackType)) { callbackName = "_on3DSMethodFinished"; } else if ("3DSMethodSkipped".equals(callbackType)) { callbackName = "_on3DSMethodSkipped"; } else { throw new IllegalArgumentException("invalid callback type"); } //Pass on the object to the page model.addAttribute("transId", transId); model.addAttribute("callbackName", callbackName); model.addAttribute("callbackParam", param); return "notify_3ds_events"; } |
/3ds-notify
への呼び出しにより返されるページnotify_3ds_events.html
という新しいHTMLファイルを、/resources/templatesディレクトリ内に 作成 します。このページのjavascriptによりcallbackFn()
が呼び出すたされます。
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> //notify parent checkout page to proceed with rest procedures. var callbackFn = parent[$('#notifyCallback').val()]; //callbackFn is defined in 3ds-notify handler method if (typeof callbackFn === 'function') { callbackFn($('#transId').val(),$('#param').val()); } </script> </body> </html> |
3DSサーバーから与えられるcallbackName
によって、3ds-web-adapter.js
内で呼び出すメソッドが異なることが分かります(ステップ8)。各メソッドについて、以下に説明します。
_onThreeDSMethodFinished
- 3DSメソッドが完了したことを通知し、_doAuth()
を呼び出します。_onThreeDSMethodSkipped
- 3DSメソッドがスキップされたことを通知し、_doAuth()
を呼び出します。
3ds-web-adapter
内の_doAuth()
は、/auth
へのPOST要求を行い、認証を実行します(ステップ9)。
この要求を処理する新しいハンドラ関数を、AuthController.java
に 追加 します。このメソッドは、threeDSRequestorTransID
とthreeDSServerTransID
を使用して/brw
へのPOST API要求を行わなければなりません(ステップ10)。3DSサーバーはAReqを作成して送信し3DS処理を開始しAResを受信し処理します(ステップ. 11)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //AuthController.java @PostMapping("/auth") public AuthResponseBRW auth(@RequestParam("id") String transId) { MerchantTransaction transaction = transMgr.findTransaction(transId); //create authentication request. AuthRequestBRW authRequest = new AuthRequestBRW(); authRequest.setThreeDSRequestorTransID(transaction.getId()); authRequest.setThreeDSServerTransID(transaction.getInitAuthResponseBRW().getThreeDSServerTransID()); String brwUrl = THREE_DS_SERVER_URL + "/brw"; AuthResponseBRW response = restTemplate.postForObject(brwUrl, authRequest, AuthResponseBRW.class); logger.info("authResponseBRW {}", response); return response; } |
/api/v1/auth/brw
に対する成功応答が得られ、transStatus
が「Y」にセットされていなければなりません(ステップ12)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | { "acsChallengeMandated":"null", "authenticationType":"null", "authenticationValue":"YXV0aCB2YWx1ZSB4eHh4eHh4eHg=", "cardholderInfo":"null", "challengeUrl":"null", "eci":"06", "errorCode":"null", "errorComponent":"null", "errorDescription":"null", "errorDetail":"null", "errorMessageType":"null", "threeDSServerTransID":"52056514-7504-40c7-886f-2a0452d8edbd", "transStatus":"Y", "transStatusReason":"null" } |
有効なchallengeUrl
がセットされており、transStatus
は「C」にセットされてます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | { "acsChallengeMandated":"Y", "authenticationType":"01", "authenticationValue":"null", "cardholderInfo":"null", "challengeUrl":"https://uat-callback.testlab.activeserver.cloud/api/v1/auth/brw/challenge/init?txid=c8a32fb7-9556-4242-896b-562ee8ca25df", "eci":"null", "errorCode":"null", "errorComponent":"null", "errorDescription":"null", "errorDetail":"null", "errorMessageType":"null", "threeDSServerTransID":"c8a32fb7-9556-4242-896b-562ee8ca25df", "transStatus":"C", "transStatusReason":"null" } |
/resources/test_scenario.txtにはチャレンジウィンドウで要求されるワンタイムパスコードも示されていますが、callbackType
AuthResultReady
の処理機能がまだ実装されていないためエラーになります。この機能は、次のステップで実装します。
ポイント
transStatus
が「C」である場合、3ds-web-adapter.js
はstartChallenge(url)
を呼び出し、startChallenge(url)
は、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'); } |
iframe
のクラスはh-100
、w-100
にセットされていることが分かります。これは、height: 100%!important
、width: 100%!important
のcssスタイルを実装するためのブートストラップデフォルトクラスです。この設定が必要なのは、ACSから提供されるコンテンツに応じてiframe
のサイズを変更しなければならないためです。チャレンジ画面は次に示すスクリーンショットのようになるはずです。
解説
/resources/test_scenario.txtはデモのためにのみ示すものであり、本番環境では、ACSは、提供されたカード番号でなく取得したカード会員情報に基づいてリスクベースの認証を実行します。同様に、認証の方法(ワンタイムパスワード、生体認証等)は、カード会員のイシュアーにより決定され実装されます。
ステップ3: 認証結果の取得¶
前のステップで説明しましたように、認証結果をカード会員に表示するためには、認証結果を要求する必要があります。フリクションレスフローでもこれが必要になります(次の警告欄を参照)。
なぜ認証結果更新が必要なのか?
フリクションレスフローの場合は、ステップ12ですでに認証結果が得られているのになぜもう一度結果を要求する必要があるのか、疑問に思われるかもしれません。これは、ステップ13で認証結果がページに転送されるためです。3ds-web-adapter
が結果を3DSリクエスターに送り返すことも可能ですが、データが安全でないと見なされます。サーバー側では常に、元の情報源である3DSサーバーから戻される結果をサーバー自身の機能により取得できなければなりません。このステップで結果の受信を要求する必要があるのは、このためです。
チャレンジフローの場合は、3DSメソッドのステータス通知と同様に3ds-notify
のエンドポイントを使用して3DSサーバーから認証結果が通知されます。
次に強調表示で示されているように、「AuthResultReady」というcallbackType
を処理するための新しいelse ifステートメントをMainController.java
に追加します。
1 2 3 4 5 6 7 8 | //MainController.java if ("3DSMethodFinished".equals(callbackType)) { callbackName = "_on3DSMethodFinished"; } else if ("3DSMethodSkipped".equals(callbackType)) { callbackName = "_on3DSMethodSkipped"; } else if ("AuthResultReady".equals(callbackType)) { callbackName = "_onAuthResult"; } |
_onAuthResultReady
はnotify-3ds-events
から呼び出され、ウィンドウを/auth/result?txid=+transId
にリダイレクトします。認証結果が必要な場合は、ハンドラー/auth/result
で/brw/result
を呼び出して結果の要求を行うことができます。
強調表示になっているコードをMainController.java
に 追加 します。
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 34 35 36 37 38 39 40 41 42 43 44 45 | import org.springframework.web.client.RestTemplate; import com.gpayments.requestor.sample_requestor.dto.activeserver.AuthResponseBRW; import com.gpayments.requestor.sample_requestor.transaction.MerchantTransaction; //MainController.java public class MainController { private static final Logger logger = LoggerFactory.getLogger(MainController.class); private final TransactionManager transMgr; private final Shop shop; private final Cart cart; private final RestTemplate restTemplate; @Autowired public MainController( TransactionManager threeDSRequestorTransactionManager, Shop shop, Cart cart, RestTemplate restTemplate) { this.transMgr = threeDSRequestorTransactionManager; this.shop = shop; this.cart = cart; this.restTemplate = restTemplate; } ... @GetMapping("/auth/result") public String result( @RequestParam("txid") String transId, Model model) { MerchantTransaction transaction = transMgr.findTransaction(transId); String resultUrl = AuthController.THREE_DS_SERVER_URL + "/brw/result?threeDSServerTransID=" + transaction.getInitAuthResponseBRW().getThreeDSServerTransID(); AuthResponseBRW response = restTemplate.getForObject(resultUrl, AuthResponseBRW.class); //convey result to the page. model.addAttribute("result", response); //make a copy of cart just for displaying model.addAttribute("cart", new Cart(cart)); // clear the actual cart content cart.clearItem("all"); return "result"; } } |
result.html
で強調表示になっているコードは、削除するかコメントアウト してください。
1 2 3 4 5 6 7 8 9 10 11 12 | <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">Thank you for your purchase!</h4>--> <!--<p class="card-text">Want to continue shopping? Press "Back to Home".</p>--> <a href="/" class="btn btn-primary btn-block">Back to Home</a> </div> </div> </div> |
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> |
成功
ご苦労様でした。これで、ActiveServerを組み込んだ加盟店決済ページが動作する状態を実現できました。もう一度アプリを実行してみてください。成功したことを示す結果ページが開き、トランザクションステータス、ECI、CAVVが表示されるはずです。
新しい結果画面は、次に示すスクリーンショットのようになります。
ヒント
この処理の後は通常、トランザクションを完了させるため、トランザクションステータス、ECI、CAVVを使用したオーソリを実行することになります。
最終的なデモコード¶
最終的なデモコードは、GPaymentsサンプルコードパッケージにある/finalCode
フォルダーからご確認いただけます。このコードは、ActiveServerでデフォルト設定のままで動作しますので、このガイドに従ってアプリを実行するだけです。
コード要約¶
3DSリクエスターデモコードは、以下のような複数のエンドポイントとコンポーネントを実装します。
-
/auth/init
- このエンドポイントは3ds-web-adapter.js
から呼び出され、認証開始要求を受け付け、3DS2認証処理を開始します。3DSリクエスターは、ActiveServerの認証開始APIである/api/v1/auth/brw/init/{messageCategory}
を呼び出します。 -
/auth
- このエンドポイントは3ds-web-adapter.js
から呼び出され、認証実行要求を受け付け、ブラウザ情報の収集後に3DS2認証を実行し、オプションで3DSメソッドを実行します。3DSリクエスターは、ActiveServerの認証APIである/api/v1/auth/brw
を呼び出します。 -
/3ds-notify
- ActiveServerから3DSリクエスターに、3DSメソッド実行ステータス、認証結果、チャレンジ結果を通知できるようにします。 -
3ds-web-adapter.js
- 3DSリクエスター処理のスキャフォールディング用に作成された簡潔なJavaScriptのライブラリ。 -
Classes under package
com.gpayments.requestor.sample_requestor.dto.activeserver
- ActiveServer APIのDTO (データ転送オブジェクト)
加盟店ウェブサイトに組み込まれる場合、3DSリクエスターのデモコードは、加盟店サイトの決済ページに組み込むための3ds-web-adapter.js
を提供します。加盟店ウェブサイトは、3ds-web-adapter.js
でthreeDSAuth()
を呼び出してカード会員情報をセットし、認証処理を開始します。加盟店ウェブサイトは、3DSリクエスターが関連するコールバックURLと実行すべき3DSメソッドをセットできるようにするためのiframe
を提供する必要があります。
認証処理が終わると、3DSリクエスターは、イベントコールバックURLである/3ds-notify
を使用して認証結果を通知します。この後、決済代行会社または加盟店はオーソリ処理に進むことができます。
ディレクトリツリー¶
次に示すのは最終的な加盟店決済サイトのディレクトリツリーです。チュートリアル終了時のsampleCode
は次のディレクトリのようになります。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | // Final demo code directory tree |- java.com.gpayments.requestor.sample_requestor | |- config | | |- RestClientConfig.java | | | |- dto | | |- activeserver | | | |- AcctInfo.java | | | |- AuthRequestBRW.java | | | |- AuthResponseBRW.java | | | |- CardholderInformation.java | | | |- InitAuthRequestBRW.java | | | |- InitAuthResponseBRW.java | | | |- MerchantRiskIndicator.java | | | |- PhoneNumber.java | | | |- ThreeDSRequestorAuthenticationInfo.java | | | | | |- CardholderInfo.java | | |- Cart.java | | |- Item.java | | |- Shop.java | | | |- transaction | | |- MerchantTransaction.java | | |- TransactionManager.java | | | |- AuthController.java | |- MainController.java | |- SampleRequestorApplication.java | |- resources |-static | |-css | | |-spinner.css | | |-style.css | | | |-images | | |-apple.jpg | | |-banana.jpg | | |-pineapple.jpg | | |-visa-logo.jpg | | | |-js | | |-3ds-web-adapter.js | | -certs | |- client_certificate.p12 | |- cacerts.jks | |-templates | |- checkout.html | |- index.html | |- notify_3ds_events.html | |- result.html | |-application.properties |-test_scenarios.txt |
ライトボックスのチャレンジウィンドウ¶
チュートリアルではチャレンジ画面がインライン要素として横並びに表示されていましたが、ユーザーのウェブサイトのデザインによってはポップアップウィンドウ内にチャレンジウィンドウを表示さ せたい場合もあります。UI自体はACSにより提供されますので、ユーザーがUIの実装について心配する必要はありません。
checkout.html
を 開き 、次に示すようなコード部分を見つけてください。これはチャレンジウィンドウを定義している部分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <!--checkout.html--> <div class="card d-none" id="checkoutCard"> <div class="challengeContainer border"> <div class="spinner row h-100 justify-content-center align-items-center"> <div class="col"> <div class="sk-fading-circle"> <div class="sk-circle1 sk-circle"></div> <div class="sk-circle2 sk-circle"></div> <div class="sk-circle3 sk-circle"></div> <div class="sk-circle4 sk-circle"></div> <div class="sk-circle5 sk-circle"></div> <div class="sk-circle6 sk-circle"></div> <div class="sk-circle7 sk-circle"></div> <div class="sk-circle8 sk-circle"></div> <div class="sk-circle9 sk-circle"></div> <div class="sk-circle10 sk-circle"></div> <div class="sk-circle11 sk-circle"></div> <div class="sk-circle12 sk-circle"></div> </div> <div class="text-center"><img class="w-25" src="images/visa-logo.png"/></div> </div> </div> </div> </div> |
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 | <!--checkout.html--> <!--<div class="card d-none" id="checkoutCard">--> <!--<div class="challengeContainer border">--> <div class="spinner row h-100 justify-content-center align-items-center"> <div class="col"> <div class="sk-fading-circle"> <div class="sk-circle1 sk-circle"></div> <div class="sk-circle2 sk-circle"></div> <div class="sk-circle3 sk-circle"></div> <div class="sk-circle4 sk-circle"></div> <div class="sk-circle5 sk-circle"></div> <div class="sk-circle6 sk-circle"></div> <div class="sk-circle7 sk-circle"></div> <div class="sk-circle8 sk-circle"></div> <div class="sk-circle9 sk-circle"></div> <div class="sk-circle10 sk-circle"></div> <div class="sk-circle11 sk-circle"></div> <div class="sk-circle12 sk-circle"></div> </div> <div class="text-center"><img class="w-25" src="images/visa-logo.png"/></div> </div> </div> </div> </div> <!--Cardholder information --> <div class="card" id="cardholderInfoCard"> |
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 | <!--checkout.html--> <!--<div class="card d-none" id="checkoutCard">--> <!--<div class="challengeContainer border">--> <div class="modal fade" id="authBox" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog h-100 d-flex flex-column justify-content-center my-0" role="document"> <div class="modal-content"> <div class="modal-body challengeContainer"> <div class="spinner row h-100 justify-content-center align-items-center"> <div class="col"> <div class="sk-fading-circle"> <div class="sk-circle1 sk-circle"></div> <div class="sk-circle2 sk-circle"></div> <div class="sk-circle3 sk-circle"></div> <div class="sk-circle4 sk-circle"></div> <div class="sk-circle5 sk-circle"></div> <div class="sk-circle6 sk-circle"></div> <div class="sk-circle7 sk-circle"></div> <div class="sk-circle8 sk-circle"></div> <div class="sk-circle9 sk-circle"></div> <div class="sk-circle10 sk-circle"></div> <div class="sk-circle11 sk-circle"></div> <div class="sk-circle12 sk-circle"></div> </div> <div class="text-center"><img class="w-25" src="images/visa-logo.png"/></div> </div> </div> </div> </div> </div> </div> <!--Cardholder information --> <div class="card" id="cardholderInfoCard"> |
checkout.html
の最後まで下にスクロールすると、checkout()
関数の中に次のようなコードがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //checkout.html function checkout() { .... var purchaseInfo = { acctNumber: $('#cardNumber').val(), purchaseAmount: '100', purchaseCurrency: '840', //USD expiryDate: $('#cardExpiry').val() }; //remove cardholder information class, checkout button and show spinner effect $("#checkoutButton").remove(); $("#cardholderInfoCard").remove(); $("#checkoutCard").removeClass("d-none"); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //checkout.html function checkout() { .... var purchaseInfo = { acctNumber: $('#cardNumber').val(), purchaseAmount: '100', purchaseCurrency: '840', //USD expiryDate: $('#cardExpiry').val() }; //remove cardholder information class, checkout button and show spinner effect $("#checkoutButton").remove(); //$("#cardholderInfoCard").remove(); //$("#checkoutCard").removeClass("d-none"); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
コメントアウトした部分の代わりにポップアップチャレンジウィンドウ用のポップアップボックスを表示するよう、第17行を追加 します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //checkout.html function checkout() { .... var purchaseInfo = { acctNumber: $('#cardNumber').val(), purchaseAmount: '100', purchaseCurrency: '840', //USD expiryDate: $('#cardExpiry').val() }; //remove cardholder information class, checkout button and show spinner effect $("#checkoutButton").remove(); //$("#cardholderInfoCard").remove(); //$("#checkoutCard").removeClass("d-none"); $('#authBox').modal(); threeDSAuth(transId, cardHolderInfo, purchaseInfo); } |
作成したコードを 再実行 すると、チャレンジ画面がポップアップウィンドウになったことが分かります。カード番号は、/resources/test_scenario.txt内で使用可能なチャレンジシナリオカードの範囲に変更してください。
デモコードのデフォルト設定¶
最終的なデモコードで設定されているデフォルト値を以下に示します。順を追ったチュートリアルの中で、この項を参照することになるかもしれません。
- THREE_DS_SERVER_URL=https://uat.testlab.activeserver.cloud/api/v1/auth
- THREE_DS_REQUESTOR_URL=http://localhost:8082
- CERTIFICATE_PASSWORD=123456
サポート¶
本書をお読みになった後に質問事項がある場合はサポートさせていただきますので、techsupport@gpayments.comにて弊社あてにEメールをお送りください。