使用 3DS JavaScript API 实施 3DS 集成
本指南概述了使用 3DS JavaScript (JS) API 将 3DS 添加到网关集成所需的所有步骤,包括如何使用身份验证结果处理付款。
步骤 1:创建和更新会话
3DS JS 使用基于会话的身份验证。作为第一步,您必须创建会话,然后您可以使用希望存储在会话中的请求字段和值更新会话。
您可以使用 Create Session 调用来创建会话。这是一个服务器端 API 调用,是与 JS API 集成的一个先决条件。它返回以下字段:
session.id
:您必须在后续请求中提供以引用会话内容的唯一会话识别码。session.authenticationLimit
:付款人浏览器可以提交的交易请求的数量限制。您可以在请求中提供一个值或使用网关的默认值。默认情况下,网关将此值设置为 5,不过您可以提供的最大值是 25。此限制可以阻止恶意用户将身份验证请求用作潜在的卡攻击,以及通过提交大量(有可能是可计费交易)交易对您的网站执行拒绝服务 (DoS) 攻击。
请注意,您发起的任何身份验证重试都会接受身份验证限制检查。session.aes256Key
:您可以用来解密通过付款人浏览器或移动设备传递到您网站的敏感数据的密钥。session.version
:您可以使用此字段来实现会话内容的乐观锁。session.updateStatus
:上次尝试修改会话的结果的摘要。
您可以使用 Update Session 调用在会话中添加或更新字段。它允许您将付款和付款人数据添加到会话中,数据随后可以成为确定在身份验证操作中与付款人关联的风险的输入。会话中需要以下字段:
参数 | 存在 | 说明 |
---|---|---|
session.id 、sourceOfFunds.provided.card.* 或 sourceOfFunds.token |
必需 | 用于付款的卡的详细信息。 请注意,您还可以使用网络令牌和设备付款令牌作为付款人身份验证中的资金来源。有关详细信息,请参见常见问题。 |
order.amount |
必需 | 订单总额。 |
order.currency |
必需 | 订单货币。 |
transaction.id |
必需 | 此支付身份验证的唯一识别码。 |
order.id |
必需 | 此订单的唯一识别码。 |
authentication.channel |
必需 | 发起身份验证请求的通道。您可以指定以下其中一项:
|
authentication.redirectResponseUrl |
可选 | 您希望在完成付款人身份验证流程后将付款人重定向到的 URL。您必须提供此 URL,除非您确定不会与付款人进行任何交互。 |
authentication.purpose |
可选 | 默认情况下,此字段设置为“PAYMENT_TRANSACTION”,指示在处理卡付款时要执行身份验证。不过,您可以指定其他目的来指示非支付身份验证。请参见提交非支付身份验证请求。 |
authentication.acceptVersions |
可选 | 您将为此次付款接受的 3DS 版本。如果未指定版本,3DS1 和 3DS2 都将被接受。网关将使用 3DS2(如果发卡机构和卡支持),仅当 3DS2 不可用时才会选择 3DS1。如果两者都不可用,身份验证将不会继续。请注意,回退场景仅适用于有 3DS1 扩展的市场。 |
order.merchantCategoryCode |
可选 | 在您希望覆盖在收单行链接上配置的默认值时提供商家类别代码。 |
步骤 2:初始化 API
引用来自网关服务器的 3DS JS API (threeDS.js
)。这会将 ThreeDS
对象放入窗口/全局名称空间。
创建会话后,使用 configure( )
方法初始化 API。此方法应该在页面加载过程中或 DOM 处于就绪状态时调用。对于页面加载应该只调用一次。调用此方法后,3DS JS 将提供配置值作为成员变量。
您可以通过调用 configure() 方法来初始化 3DS JS API,在映射对象中使用以下强制字段作为参数:
merchantId
:您在网关上的商家识别码。sessionId
:您使用 Create Session 调用创建的会话 ID。containerId
:API 将在其中插入隐藏的内嵌框架您的 html 中的 <div> ID。callback
:API 初始化后将调用的函数。configuration
:JSON 值支持数据元素,如 userLanguage(可选)、REST API 版本 (wsVersion)。
<html> <head> <script src="https://qnbalahli.test.gateway.mastercard.com/static/threeDS/1.3.0/three-ds.min.js" data-error="errorCallback" data-cancel="cancelCallback"> </script> <script type="text/javascript"> //The output of this call will return 'false', since the API is not configured yet console.log(ThreeDS.isConfigured()); /** Configure method with the configuration{} parameter set and demonstrates the state change of the ThreeDS object before and after the configure method is invoked. */ ThreeDS.configure({ merchantId: {merchantId}, sessionId: {sessionId}, containerId: "3DSUI", callback: function () { if (ThreeDS.isConfigured()) console.log("Done with configure"); }, configuration: { userLanguage: "en-AU", //Optional parameter wsVersion: 72 } }); //The output of this call will return 'true', since the API is configured console.log(ThreeDS.isConfigured()); //The output of the following code might look like "ThreeDS JS API Version : 1.2.0" console.log("ThreeDS JS API Version : " + ThreeDS.version); </script> </head> <body> <div id="3DSUI"></div> </body> </html>
步骤 3:发起身份验证
将所有付款人和付款数据收集到一个会话中后,您可以通过调用 initiateAuthentication()
方法来发起身份验证。此方法确定给定卡可用的付款人身份验证的版本,基于以下信息:
- 在您的商家配置文件上配置的 3DS 版本
- 卡类型
- 您在请求中指定的首选项
- 卡已注册的 3DS 版本,以及
- 您或您的支付服务提供商配置的 3DS 交易筛选规则。
此操作还支持出于某些目的执行任何后台活动(如 3DS2 ACS 调用),如收集其他付款人数据以支持后续的 authenticatePayer()
方法。
authenticatePayer()
方法之前完成,建议您在结账流程中尽早调用 initiateAuthentication() 方法,并立即对响应采取行动。通常是在付款人在结账页完成卡号输入时,例如,“卡号”输入字段的“onBlur”事件,或者在从根据付款人的账户记录的卡中选择卡时(如果您的网站具有卡存档功能)。请至少等待十秒钟让 ACS 方法调用完成。您可以通过在 initiateAuthentication()
方法中提供以下强制字段来发起身份验证:
- transactionId:此支付身份验证的唯一识别码。
- orderId:此订单的唯一识别码。
- callback:回调函数。
- optionalParams:(可选)包含任何其他 Initiate Authentication REST API 请求字段(如 correlationId)的参数。
如果付款人的 3DS 身份验证可用,回调函数的 data
参数中将返回以下字段。否则,响应将包含错误。
data.restApiResponse
:包含来自 Initiate Authentication REST API 调用的原始响应。data.correlationId
:用于发起 Initiate Authentication REST API 调用的最后一个关联 ID。您可以使用它匹配响应和请求。data.gatewayRecommendation
data.authenticationVersion
:如果身份验证可用,返回 3DS1 或 3DS2。请注意,回退场景仅适用于有 3DS1 扩展的市场。
要确定下一步,请查看 gatewayRecommendation 字段中提供的网关建议。请注意,具体建议仅基于您或您的支付服务提供商配置的 3DS 交易筛选规则。
gatewayRecommendation |
下一步 |
---|---|
PROCEED | 您可以使用 authenticatePayer( ) 方法调用继续对付款人进行身份验证。 |
RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS | 向付款人询问备用付款详细信息(例如,新卡或另一个付款方式),然后使用新详细信息重新提交请求。不要重新提交相同的请求。 |
var optionalParams = { sourceOfFunds: { type: "CARD" }, order: { walletProvider: "MASTERPASS_ONLINE" } }; ThreeDS.initiateAuthentication({orderId}, {transactionId}, function (data) { if (data && data.error) { var error = data.error; //Something bad happened, the error value will match what is returned by the Authentication API console.error("error.code : ", error.code); console.error("error.msg : ", error.msg); console.error("error.result : ", error.result); console.error("error.status : ", error.status); } else { console.log("After Initiate 3DS ", data); //data.response will contain information like gatewayRecommendation, authentication version, etc. console.log("REST API raw response ", data.restApiResponse); console.log("Correlation Id", data.correlationId); console.log("Gateway Recommendation", data.gatewayRecommendation); console.log("HTML Redirect Code", data.htmlRedirectCode); console.log("Authentication Version", data.authenticationVersion); switch (data.gatewayRecommendation) { case "PROCEED": authenticatePayer();//merchant's method break; case "RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS": tryOtherPayment();//Card does not support 3DS and transaction filtering rules require 3DS on this transaction: Ask the payer to select a different payment method. break; } } }, optionalParams);
{ "authentication":{ "3ds2":{ "methodCompleted":false, "methodSupported":"SUPPORTED" }, "redirect":{ "customized":{ "3DS":{ "methodPostData":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==", "methodUrl":"<method_url>" } } }, "redirectHtml":"<div id=\"initiate3dsSimpleRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <iframe id=\"methodFrame\" name=\"methodFrame\" height=\"100\" width=\"200\" > </iframe> <form id =\"initiate3dsSimpleRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/method\" target=\"methodFrame\"> <input type=\"hidden\" name=\"threeDSMethodData\" value=\"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==\" /> </form> <script>document.getElementById(\"initiate3dsSimpleRedirectForm\").submit();</script> </div>", "version":"3DS2" }, "order":{ "currency":"AUD", "status":"AUTHENTICATION_INITIATED" }, "response":{ "gatewayCode":"AUTHENTICATION_IN_PROGRESS", "gatewayRecommendation":"PROCEED" }, "result":"SUCCESS", "sourceOfFunds":{ "provided":{ "card":{ "number":"512345xxxxxx0008" } }, "type":"CARD" }, "transaction":{ "authenticationStatus":"AUTHENTICATION_AVAILABLE" }, "version":"72" }
步骤 4:对付款人进行身份验证
如果 Initiate Authentication 响应指示身份验证可用 (transaction.authenticationStatus=AUTHENTICATION_AVAILABLE),您可以调用 authenticatePayer()
方法。您应该在付款人点击结账页面的“立即付款”按钮时调用此项。
您必须通过提供以下强制字段来调用 authenticatePayer()
方法:
orderId
:与之前的initiateAuthentication()
方法相同的 orderId。transactionId
:与之前的initiateAuthentication()
方法相同的 transactionId。callback
:回调函数。optionalParams
:(可选)包含任何其他 Authenticate Payer REST API 请求字段(如 billing 和 shipping)的参数。
回调函数的 data
参数中返回以下字段:
data.restApiResponse
:包含来自 Authentication Payer REST API 调用的原始响应。data.correlationId
:用于发起 Authentication Payer REST API 调用的最后一个关联 ID。您可以使用它匹配响应和请求。data.gatewayRecommendation
data.htmlRedirectCode
:网关始终返回此字段用于插入到向付款人显示的页面中。
要确定下一步,请查看回调中返回的 gatewayRecommendation
字段中提供的网关建议。请注意,具体建议仅基于您或您的支付服务提供商配置的 3DS 交易筛选规则。
gatewayRecommendation |
下一步 |
---|---|
PROCEED | 您可以继续完成身份验证流程(质询流)或继续完成付款(无障碍流)。如果对付款的授权成功,继续过账资金,如果适用,则发货。 |
DO_NOT_PROCEED_ABANDON_ORDER | 不要再次提交相同的请求。支付服务提供商、组织或发卡机构要求您放弃订单。 |
RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS | 向付款人询问备用付款详细信息(例如,新卡或另一个付款方式),然后使用新详细信息重新提交请求。不要重新提交相同的请求。 |
如果网关建议您 PROCEED
,则将 htmlRedirectCode
响应字段的内容粘贴到显示给付款人的页面中。
无障碍流
这会将付款人的浏览器直接重定向回您的网站。您可以继续向网关提交后续付款。网关将获取与付款相关的身份验证数据,并确保仅在所有 3DS 交易筛选规则(由您或您的支付服务提供商配置)都通过的情况下付款才会被处理。
质询流
这会将付款人的浏览器重定向到 ACS,那里将显示发卡机构的质询 UI,之后付款人将被重定向回您的网站。在付款人的浏览器返回到您的网站后,以下字段将在回调中返回。
- orderId
- transactionId
- gatewayRecommendation
- restApiResponse
您可以使用 gatewayRecommendation
字段中返回的值来确定身份验证结果。请注意,具体建议仅基于您或您的支付服务提供商配置的 3DS 交易筛选规则。
gatewayRecommendation |
下一步 |
---|---|
PROCEED | 您可以继续处理付款,因为同意进行身份验证。如果对付款的授权成功,继续过账资金,如果适用,则发货。 |
DO_NOT_PROCEED_ABANDON_ORDER | 不要再次提交相同的请求。支付服务提供商、组织或发卡机构要求您放弃订单。 |
RESUBMIT_WITH_ALTERNATIVE_PAYMENT_DETAILS | 向付款人询问备用付款详细信息(例如,新卡或另一个付款方式),然后使用新详细信息重新提交请求。不要重新提交相同的请求。 |
restApiResponse
中返回的字段取决于实际执行的流(无障碍与质询)以及身份验证请求如何发起 (authentication.channel)。
对于经过会话身份验证的请求,将对响应进行筛选以删除与付款人无关的数据,然后仅返回加入白名单的字段。有关详细信息,请参见经过会话身份验证的操作。
高级集成
在 authenticatePayer()
方法完成后付款人的浏览器向您的网站提交的请求将以参数表示,让您可以确定身份验证结果。单独的身份验证参数(例如,authentication.3ds2.transactionStatus.data
)在高级集成中,或需要在通过另一个网关处理的付款中提供身份验证数据时可能很有用。请参见高级付款会话集成。
var optionalParams = { fullScreenRedirect: true, billing: { address: { city: "London", country: "GBR" } } }; ThreeDS.authenticatePayer({orderId}, {transactionId}, function (data) { if (!data.error) { //data.response will contain all the response payload from the AUTHENTICATE_PAYER call. console.log("REST API response ", data.restApiResponse); console.log("HTML redirect code", data.htmlRedirectCode); displayReceipt(data); } }, optionalParams); function displayReceipt(apiResponse) { var responseBody = { "apiResponse": apiResponse }; var xhr = new XMLHttpRequest(); xhr.open('PUT', '3dsreceipt', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState == XMLHttpRequest.DONE) { document.documentElement.innerHTML = this.response; } } xhr.send(JSON.stringify(responseBody)); }
{ "authentication":{ "3ds":{ "transactionId":"6dfa4509-1bf2-425b-965b-d44dd11f5f91" }, "3ds2":{ "3dsServerTransactionId":"8c4a911c-289a-46c2-a615-887e1cc01a6a", "acsTransactionId":"2a8234c9-e8ac-449d-a693-97a113b491fc", "directoryServerId":"A000000004", "dsTransactionId":"6dfa4509-1bf2-425b-965b-d44dd11f5f91", "methodCompleted":false, "methodSupported":"SUPPORTED", "protocolVersion":"2.1.0", "requestorId":"test2ID", "requestorName":"test2Name", "transactionStatus":"C" }, "method":"OUT_OF_BAND", "payerInteraction":"REQUIRED", "redirect":{ "customized":{ "3DS":{ "acsUrl":"https://<host_name>/acs/v2/prompt", "cReq":"eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImNhODM1ZDQxLTBlMDktNGI3OC1hNmUyLWQwZjJiNjFlZjBjOCJ9" } }, "domainName":"<domain_name>" }, "redirectHtml":"<div id=\"threedsChallengeRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <form id =\"threedsChallengeRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/prompt\" target=\"challengeFrame\"> <input type=\"hidden\" name=\"creq\" value=\"eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImNhODM1ZDQxLTBlMDktNGI3OC1hNmUyLWQwZjJiNjFlZjBjOCJ9\" /> </form> <iframe id=\"challengeFrame\" name=\"challengeFrame\" width=\"100%\" height=\"100%\" ></iframe> <script id=\"authenticate-payer-script\"> var e=document.getElementById(\"threedsChallengeRedirectForm\"); if (e) { e.submit(); e.remove(); } </script> </div>", "version":"3DS2" }, "correlationId":"test", "device":{ "browser":"MOZILLA", "ipAddress":"127.0.0.1" }, "merchant":"TEST_3DS2-1", "order":{ "amount":100, "authenticationStatus":"AUTHENTICATION_PENDING", "creationTime":"2021-04-13T02:22:59.113Z", "currency":"AUD", "id":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "lastUpdatedTime":"2021-04-13T02:44:07.161Z", "merchantCategoryCode":"1234", "status":"AUTHENTICATION_INITIATED", "totalAuthorizedAmount":0, "totalCapturedAmount":0, "totalRefundedAmount":0, "valueTransfer":{ "accountType":"NOT_A_TRANSFER" } }, "response":{ "gatewayCode":"PENDING", "gatewayRecommendation":"PROCEED" }, "result":"PENDING", "sourceOfFunds":{ "provided":{ "card":{ "expiry":{ "month":"1", "year":"39" }, "number":"512345xxxxxx0008", "scheme":"MASTERCARD" } }, "type":"CARD" }, "timeOfLastUpdate":"2021-04-13T02:44:07.161Z", "timeOfRecord":"2021-04-13T02:22:59.113Z", "transaction":{ "acquirer":{ "merchantId":"99554411" }, "amount":100, "authenticationStatus":"AUTHENTICATION_PENDING", "currency":"AUD", "id":"42090084", "type":"AUTHENTICATION" }, "version":"60" }
步骤 5:在付款操作中使用身份验证结果
当 authenticatePayer()
方法的结果指示您可以继续处理付款时 (gatewayRecommendation=PROCEED),您可以发起 Authorize 或 Pay 操作。除了标准字段外,您还必须提供以下字段:
- order.id:提供您在
initiateAuthentication()
和authenticatePayer()
方法中提供的orderId
。 - authentication.transactionId:提供您在
initiateAuthentication()
和authenticatePayer()
方法中提供的transactionId
。您无需在身份验证参数组中包括任何字段,因为当您要求执行身份验证时,网关将使用 authentication.transactionId 查找存储的身份验证结果。网关将需要的信息传送到收单行。
URL | https://qnbalahli.test.gateway.mastercard.com/api/rest/version/<version>/merchant/<your_merchant_ID>/order/<your_order_ID>/transaction/<unique_transaction_ID> |
HTTP 方法 | PUT |
{ "apiOperation":"PAY", "authentication":{ "transactionId":"<your_transaction_ID>" }, "order":{ "amount":"100", "currency":"AUD", "reference":"<your_order_ID>" }, "sourceOfFunds":{ "provided":{ "card":{ "number":"<card_number>", "expiry":{ "month":"1", "year":"39" } } }, "type":"CARD" }, "transaction":{ "reference":"<your_order_ID>" } }
{ "authentication":{ "3ds":{ "acsEci":"02", "authenticationToken":"kHyn+7YFi1EUAREAAAAvNUe6Hv8=", "transactionId":"39c25b96-7bc3-4586-bee8-056479fed3af" }, "3ds2":{ "dsTransactionId":"39c25b96-7bc3-4586-bee8-056479fed3af", "protocolVersion":"2.1.0", "transactionStatus":"Y" }, "transactionId":"249213216", "version":"3DS2" }, "authorizationResponse":{ "posData":"1605S0100130", "transactionIdentifier":"TidTest" }, "device":{ "browser":"MOZILLA", "ipAddress":"127.0.0.1" }, "gatewayEntryPoint":"WEB_SERVICES_API", "merchant":"TEST_3DS2-1", "order":{ "amount":100.00, "authenticationStatus":"AUTHENTICATION_SUCCESSFUL", "chargeback":{ "amount":0, "currency":"AUD" }, "creationTime":"2021-04-13T02:11:06.102Z", "currency":"AUD", "id":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "lastUpdatedTime":"2021-04-13T02:11:57.049Z", "merchantAmount":100.00, "merchantCategoryCode":"1234", "merchantCurrency":"AUD", "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "status":"CAPTURED", "totalAuthorizedAmount":100.00, "totalCapturedAmount":100.00, "totalRefundedAmount":0.00 }, "response":{ "acquirerCode":"00", "gatewayCode":"APPROVED" }, "result":"SUCCESS", "sourceOfFunds":{ "provided":{ "card":{ "brand":"MASTERCARD", "expiry":{ "month":"1", "year":"39" }, "fundingMethod":"CREDIT", "issuer":"<issuer>", "number":"512345xxxxxx0008", "scheme":"Mastercard", "storedOnFile":"NOT_STORED" } }, "type":"CARD" }, "timeOfLastUpdate":"2021-04-13T02:11:57.049Z", "timeOfRecord":"2021-04-13T02:11:56.973Z", "transaction":{ "acquirer":{ "batch":1, "id":"<acquirer_id>", "merchantId":"99554411" }, "amount":100.00, "authenticationStatus":"AUTHENTICATION_SUCCESSFUL", "authorizationCode":"028941", "currency":"AUD", "id":"1", "receipt":"1908266016", "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496", "source":"INTERNET", "stan":"496", "terminal":"1234", "type":"PAYMENT" }, "version":"60" }
常见问题
有关 3D 验证的一般常见问题,请参见身份验证常见问题。
测试您的集成
要测试您的集成,您可以在生产环境中使用测试商家配置文件,具体请参见测试您的集成。