3DSリクエスター
ActiveSDKを実装するには、加盟店サイトはバックエンドに3DS Requestorを実装する必要があります。以下の図はActiveSDK、3DS Requestor、およびその他のコンポーネントとの関係性を表します。EMVCo 3D Secure 2仕様書に基づき、加盟店アプリと3DS Server間の通信は相互認証される必要があります。そのため、バックエンドには3DS Serverと相互TLSコネクションを確立するための3DS Requestorを実装する必要があります。
このドキュメントでは、ActiveSDKを弊社の3DS Requestorサンプル・コードと統合するプロセスについて説明します。このデモでは、3DS Requestorが接続する3DS ServerはActiveServerになります。ただし、3DS Requestorのサンプル・コードを修正すればどの3DS Serverにも接続することができます。
以下はこのガイドを使用するための前提条件です:
- このいずれに関する知識: Java、PHP、C#、もしくはGo
サンプル・コードをチェックアウトして実行する¶
3DS Requestorサンプル・コードはダウンロード・ページよりダウンロードできます。クライアント証明書の取得および3DSリクエスターデモの設定の手順を参照して、3DS Requestorを実行してから次のステップへ進んでください。
注釈
3DS Requestorサンプル・コードを実行するには、アクティブ化されて稼働中のActiveServerインハウスのインスタンス(もしくはActiveServer SaaSのテナント)が必要になります。詳しくはGPayments社へご連絡ください。
3DS Requestorと3DS Server間の実装¶
3DS RequestorはモバイルアプリからAuthRequest
を受信し、そのリクエストを3DS Serverへ送信します。また、3DS Requestorは3DS ServerからAuthResponse
を受信し、その結果をモバイルアプリへ転送します。
3DS Requestorのサンプル・コードはバックエンドの実装方法を以下のサーバー側言語で提示します:
- Java: Java版はSpringbootのフレームワークを基に実現されています。Springbootに関する詳細については、
https://spring.io/projects/spring-boot
を参照してください。 - C#: C#版はASP.netを基に実現されています。
- PHP: PHP版はPHP 7.2とcURL (Client URL Library)を基に実現されています。
- Go: Go版はGo 1.12とGo Module対応を基に実現されています。全てのディペンデンシーは
go.mod
ファイルにリストアップされています。
3DS Serverと認証処理を開始する前に、3DS Requestorは3DS Serverと相互TLS認証コネクションを確立する必要があります。クライアント証明書の取得および3DSリクエスターデモの設定の手順を確認してください。
HTTPクライアントのTLS設定
- Java: TLS設定とクライアント証明書のロードは
RestClientConfig.java
クラスから参照できます。 - C#: TLS設定とクライアント証明書のロードは
RestClientHelper.cs
クラスから参照できます。 - PHP: TLS設定とクライアント証明書のロードは
RestClientConfig.php
クラスから参照できます。 - Go: TLS設定とクライアント証明書のロードは
https.go
クラスから参照できます。
認証を実行する¶
認証を実行するには、3DS Requestorは以下のタスクのために/v2/auth/app
エンドポイントを実装する必要があります:
- モバイルアプリから
AuthRequest
を受信する。 - そのリクエストを3DS Serverに転送する。
- 3DS Serverから
AuthResponse
を受信する。 - レスポンスのデータをモバイルアプリへ返却する。
//AuthControllerV2.java @PostMapping("/v2/auth/app") @ResponseBody public Message app(@RequestParam(value = "trans-type", required = false) String transType, @RequestBody Message request) { return authServiceV2.app(transType, request); } //AuthServiceV2.java public Message app(String transType, Message request) { //generate requestor trans ID String transId = UUID.randomUUID().toString(); request.put(THREE_DS_REQUESTOR_TRANS_ID, transId); String appAuthUrl = config.getAsAuthUrl() + "/api/v2/auth/app"; //Add parameter trans-type=prod in the appAuthUrl to use prod DS, otherwise use TestLabs DS //For more details, refer to: https://docs.activeserver.cloud if ("prod".equals(transType)) { appAuthUrl = appAuthUrl + "?trans-type=prod"; } logger.info("appAuthRequest on url: {}, body: \n{}", appAuthUrl, request); Message response = sendRequest(appAuthUrl, request, HttpMethod.POST); logger.info("appAuthResponse: \n{}", response); return response; }
//AuthV2Controller.cs [HttpPost, Route("v2/auth/app")] public Message app([FromBody] Message request, [FromUri(Name = "trans-type")] string transType = null) { return authServiceV2.app(transType, request); } //AuthServiceV2.cs public Message app(String transType, Message request) { //generate requestor trans ID String transId = Guid.NewGuid().ToString(); request[THREE_DS_REQUESTOR_TRANS_ID] = transId; String appAuthUrl = Config.AsAuthUrl + "/api/v2/auth/app"; //Add parameter trans-type=prod in the appAuthUrl to use prod DS, otherwise use Testlabs DS //For more details, refer to: https://docs.activeserver.cloud if ("prod".Equals(transType)) appAuthUrl = appAuthUrl + "?trans-type=prod"; logger.Info(string.Format("appAuthRequest on url: {0}, body: \n{1}", appAuthUrl, request)); Message response = (Message)RestClientHelper.PostForObject(appAuthUrl, request, typeof(Message)); logger.Info(string.Format("appAuthResponse: \n{0}", response)); return response; }
<?php //AuthControllerV2.php public function app() { $requestData = Utils::_getJsonData(); $authAppUrl = "/api/v2/auth/app"; $transType = $_GET["trans-type"]; if (!empty($transType) && $transType == "prod") { $authAppUrl = $authAppUrl . "?trans-type=prod"; } $response = $this->restTemplate->post($authAppUrl, $requestData); Utils::_returnJson($response->getBody()->getContents()); }
//api-v2.go //AuthControllerV2 routers v2 r.POST("/v2/auth/app", func(c *gin.Context) { var message Message err := c.ShouldBindJSON(&message) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } //adding requestorTransId message[ThreeDSRequestorTransId] = uuid.New() callASAPI(asSession{ message: message, url: appendTransTypeIfNecessary("/api/v2/auth/app", c), context: c, httpClient: httpClient, config: config}) })
注目
このサンプル・コードは、AuthRequest
をActivesServerへ送信するためのものです。ActiveServerのAuthRequest
のデータ構造を確認するには、APIドキュメントを参照してください。他社の3DS ServerへAuthRequest
を送信する際は該当製品のAPIドキュメントを参照してください。
ActiveServerを使用するお客様へ
デフォルトでは、上記URLはテスト目的でAuthRequest
をGPayments TestLabsへ送信します。本番環境に移行する際にAPIリクエストを各国際ブランドのDirectory Serverへ送信するには、trans-type
クエリー・パラメーターをそのAPI URLに追加する必要があります。使用方法については、APIの説明を参照してください。
Master Auth API クライアント証明書を使用して、加盟店の代わりにBusiness Adminユーザーを認証する場合、バックエンドはHTTPリクエストにAS-Merchant-Token
フィールドを含んだHTTPヘッダーを追加する必要があります。なお、これを加盟店プロフィールで設定されたmerchantTokenへ設定する必要があります。実装方法の詳細については、こちらを参照してください。
認証結果を取得する¶
フリクションレス・フローの場合、認証結果は認証実行処理が終了する際にモバイルアプリへ返却されます。
チャレンジ・フローの場合、認証実行処理が終了する際はモバイルアプリへtransStatus=C
が返却され、ActiveSDKとACSの間にチャレンジ処理が実行されます。チャレンジ処理が終了する際、モバイルアプリは/v2/auth/result
エンドポイントを呼び出し、認証結果を取得します。3DS Requestorはその結果を取得し、モバイルアプリへ返却するためには、ActiveServerへリクエストを送信する必要があります。
//AuthControllerV2.java @ResponseBody @GetMapping("/v2/auth/brw/result") public Message resultBRW(@RequestParam("txid") String serverTransId) { return authServiceV2.getBRWResult(serverTransId); } //AuthServiceV2.java public Message getBRWResult(String serverTransId) { //ActiveServer url for Retrieve Results String resultUrl = config.getAsAuthUrl() + "/api/v2/auth/brw/result?threeDSServerTransID=" + serverTransId; //Get authentication result from ActiveServer Message response = sendRequest(resultUrl, null, HttpMethod.GET); logger.info("authResponse: \n{}", response); return response; }
/// <summary> /// Receives the Request for authentication result request (Step 15(F) and Step 20(C)) /// Send data to ActiveServer to Retrieve Authentication Results /// </summary> /// <param name="txid"></param> /// <returns></returns> [HttpGet, Route("v2/auth/brw/result")] public Message authResult(String txid) { return authServiceV2.getBRWResult(txid); } //AuthServiceV2.cs public Message getBRWResult(String serverTransId) { //ActiveServer url for Retrieve Results string resultUrl = Config.AsAuthUrl + "/api/v2/auth/brw/result?threeDSServerTransID=" + serverTransId; //Get authentication result from ActiveServer Message result = (Message)RestClientHelper.GetForObject(resultUrl, typeof(Message)); return result; }
<?php //AuthControllerV2.php public function brwResult() { $serverTransId = $_GET["txid"]; $response = $this->authService->getBrwResult($serverTransId); //Show authentication results on result.html (Step. 17(F), Step. 28(C) or Step. 21(D), 22(D)). Utils::_returnJson($response); } //AuthServiceV2.php public function getBrwResult($serverTransId) { //ActiveServer url for Retrieve Results $resultUrl = "/api/v2/auth/brw/result?threeDSServerTransID=" . $serverTransId; //Get authentication result from ActiveServer (Step 16(F), Step 27(C) or Step 20(D)) return $this->restTemplate->get($resultUrl)->getBody(); }
//api-v2.go r.GET("/v2/auth/brw/result", func(c *gin.Context) { transId := getSessionAttribute(c, InitAuthResponse, ThreeDSServerTransId).(string) if transId == "" { c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid transId"}) return } callASAPI(asSession{ url: "/api/v2/auth/brw/result?threeDSServerTransID=" + transId, context: c, httpClient: httpClient, config: config}) }) ... }
モバイルアプリと3DS Requestor間の実装¶
モバイルアプリは3DS RequestorへAuthRequest
を送信する必要があります。以下はAndroidアプリの場合にそのリクエストを送信する際のサンプル・コードです。iOSの場合はこれと類似します。
警告
モバイルアプリと3DS Requestorの間の通信を実装するのは加盟店の役割です。安全な通信をするために、適切な認証処理の実施は必要です。
private Button purchaseBtn; private OkHttpClient client = new OkHttpClient(); ... @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... purchaseBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ... AuthenticationRequestParameters authParams = transaction .getAuthenticationRequestParameters(); PurchaseRequest appAuthReq = new PurchaseRequest(authParams, cardNumberEdit.getText().toString()); final Request request = new Request.Builder() .url(REQUESTOR_URL + "/v2/auth/app") .post(RequestBody.create(JSON, appAuthReq.toJson())) .build(); client.newCall(request).enqueue(new Callback() { ... @Override public void onResponse(Call call, Response response) throws IOException { progress.dismiss(); final String responseBody = response.body().string(); Log.d(TAG, "Success purchase request: " + responseBody); ... } } } }
3DS Requestorのトラブルシューティング¶
3DS Requestorでは、トラブルシューティングのために、フロントエンドにはアプリ・テストページが実装されています。Test pages -> App
を選択すれば、 アプリ・テストページへ移動することができます。
そのページには、テスト/デモのみの目的でダミーAuthRequest
データが事前に入力されています。Test App
ボタンを押すと、ダミー・データは3DS Requestorのバックエンドの/v2/auth/app
エンドポイントに送信されます。AuthResponse
はResponse
の部分に表示されます。ちなみに、本番で認証を実施する場合は統合された3DS SDKからAuthRequest
を起動する必要があります。