Процесс оплаты 3DS2 SDK

На приведенной ниже диаграмме показан процесс оплаты 3DS2 SDK.

Имейте в виду, что ACS многих эмитентов неправильно работают с 3DS Mobile SDK.

sequenceDiagram participant MA as Мобильное приложение participant MS as Мобильный сервер participant SDK2 as 3DS2 SDK participant PG as Платежный шлюз participant 3DS as 3DSS/ACS/DS MA ->> MS: 1. клиент создает заказ MS ->> PG: 2. регистрация заказа через API PG -->> MS: 3. уникальный номер заказа (mdOrder) MA ->> MA: 4. клиент вводит данные MA ->> MS: 5. отправка платежных данных на сервер MS ->> PG: 6. вызов платежного API с помощью threeDSSDK alt Оплата завершена PG -->> MS: 7. ответ со статусом платежа (Переход к 22) else требуется 3DS2 PG -->> MS: 8. ответ с ключами 3DS2 SDK MS ->> MA: 9. отправка ключей в мобильное приложение MA ->> SDK2: 10. инициализация 3DS2 SDK SDK2 -->> MA: 11. сбор данных устройства MA ->> MS: 12. отправка данных устройства MS ->> PG: 13. второй вызов платежного API PG -->> MS: 14. контент, подписанный ACS MS ->> MA: 15. отправка данных ACS MA ->> SDK2: 16. инициация потока Challenge SDK2 ->> ACS: 17. взаимодействие через CReq/CRes ACS -->> PG: 18. подтверждение транзакции через AReq SDK2 -->> MA: 19. процедура 3DS завершена MS ->> PG: 20. завершение оплаты 3DS2 PG ->> PG: 21. оплата end opt Callback-уведомления настроены PG -->> MS: 22. callback-уведомление end MS ->> PG: 23. проверка статуса платежа MS ->> MA: 24. отображение результата платежа клиенту
  1. Клиент создает заказ.
  2. Мобильный сервер регистрирует этот заказ в платежном шлюзе через register.do.
  3. Мобильный сервер получает в ответе уникальный номер заказа mdOrder.
  4. Клиент заполняет платежные данные.
  5. Мобильное приложение отправляет платежные данные на сервер.
  6. Мобильный сервер использует эти платежные данные для совершения платежа через paymentorder.do.
    • Передайте threeDSSDK=true, чтобы указать, что следует использовать 3DS2 SDK.
  7. Мобильный сервер получает ответ без ключей ACS. Это означает, что оплата завершена и нам нужно перейти к Шагу 22.
  8. Мобильный сервер получает ответ с ключами ACS.
    • Ответ должен содержать threeDSServerTransId и threeDSSDKKey
    • Ответ не должен содержать threeDSMethodURL, который используется в случае перенаправления через браузер на ACS.
  9. Мобильный сервер отправляет данные 3DS2 SDK в мобильное приложение
  10. Мобильное приложение инициирует 3DS2 SDK с помощью метода createTransaction.
    • directoryServerID зависит от платежной системы (для тестов можно использовать A000000003)
    • messageVersion на данный момент 2.1.0
    • pemPublicKey для Android и iOS – это сертификат pem, полученный в ответ в threeDSSDKKey на Шаге 10
    • dsRoot для Android и iOS зависит от платежной системы. Скачать тестовый ключ
  11. 3DS2 SDK собирает данные устройства и шифрует их.
  12. Мобильное приложение отправляет зашифрованные данные устройства на мобильный сервер
  13. Мобильный сервер инициирует второй вызов платежного API через paymentorder.do
    • sdkEncData зашифрованные данные устройства, которые возвращаются в методе createTransaction в 3DS2 SDK.
    • threeDSServerTransactionID возвращается в ответ на первый вызов платежа на Шаге 10 в параметре threeDSServerTransId
    • threeDSSDKReferenceNumber возвращается в методе createTransaction в 3DS2 SDK.
    • sdkEphemPubKey возвращается в методе createTransaction в 3DS2 SDK.
    • sdkAppID возвращается в методе createTransaction в 3DS2 SDK.
    • sdkTransID возвращается в методе createTransaction в 3DS2 SDK.
  14. Платежный шлюз возвращает новые специальные параметры для 3DS2 SDK.
  15. Мобильный сервер отправляет эти параметры в мобильное приложение.
  16. Мобильное приложение инициирует поток прохождения проверки с помощью метода doChallenge.
    • Параметр doChallenge acsTransactionID соответствует threeDSAcsTransactionId в ответе платежного шлюза
    • Параметр doChallenge acsRefNumber соответствует параметру threeDSAcsRefNumber в ответе платежного шлюза
    • Параметр doChallenge acsSignedContent соответствует параметру threeDSAcsSignedContent в ответе платежного шлюза
    • Параметр doChallenge 3DSServerTransactionID соответствует threeDSServerTransId в ответе платежного шлюза
  17. 3DS2 SDK связывается с ACS эмитентов через CReq/CRes API до тех пор, пока Клиент не подтвердит свой платеж.
  18. ACS отправляет RReq платежному шлюзу для подтверждения или отклонения платежа.
  19. 3DS2 SDK информирует мобильное приложение о завершении потока 3DS2 через ChallengeStatusReceiver.
  20. Мобильный сервер завершает платеж с помощью finish3dsVer2Payment.do
  21. Платежный шлюз осуществляет платеж.
  22. Платежный шлюз отправляет уведомление обратного вызова на сервер продавца, если оно настроено для продавца.
  23. Мобильный сервер проверяет окончательный статус платежа через getOrderStatusExtended.do.
  24. Мобильное приложение показывает результат платежа клиенту.

IOS

iOS-интеграция

Интеграция ThreeDS SDK

Рисунок 1. Добавление файла ThreeDSSDK.framework


Рисунок 2. Добавление файла ThreeDSSDK.framework


Конфигурация iOS

Пример ThreeDSSDK

Полный пример показан здесь: TransactionManager

import UIKit
import ThreeDSSDK

....

var _service: ThreeDS2Service = Ecom3DS2Service()

// Init ThreeDS SDK
try _service.initialize(configParameters: ConfigParameters(), locale: Locale.current.languageCode, uiCustomization: _setUpTheme())
var _sdkTransaction = try _service.createTransaction(directoryServerID: "", messageVersion: nil, publicKeyBase64: "", rootCertificateBase64: "", logoBase64: "")

// get progress view
var _sdkProgressDialog = try _sdkTransaction!.getProgressView()

// Show progress dialog
_sdkProgressDialog?.show()

// get authentication request parameters, to be sent to the payment gateway
var authParameters = _sdkTransaction!.getAuthenticationRequestParameters()
var deviceData = authParameters.getDeviceData()
var ephemeralPublickKey = authParameters.getSDKEphemeralPublicKey()
var threeDSSDKAppId = authParameters.getSDKAppID()
var threeDSSDKTransId = authParameters.getSDKTransactionID()

// if you get error during initial sdk, you can close spinner.
// _sdkProgressDialog?.close()

// Set challenge parameters and start challenge flow
let challengeParameters = ChallengeParameters()
challengeParameters.setAcsSignedContent("acsSignedContent")
challengeParameters.setAcsRefNumber("acsReferenceNumber")
challengeParameters.setAcsTransactionID("acsTransID")
challengeParameters.set3DSServerTransactionID("threeDSServerTransID")
// Start challenge flow
self._sdkTransaction?.doChallenge(challengeParameters: challengeParameters, challengeStatusReceiver: self, timeOut: 5)

// If you get error during sdk flow, you can finish sdk transaction
// _sdkTransaction?.close()

// Delegate functions
extension TransactionManager: ChallengeStatusReceiver {
  public func completed(completionEvent e: CompletionEvent) {}
  public func cancelled() {}
  public func timedout() {}
  public func protocolError(protocolErrorEvent e: ProtocolErrorEvent) {}
  public func runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}
}

Логирование

Внутренние процессы логируются с тегом SDK-ThreeDS. Вы также можете логировать свои процессы. Логирование доступно через класс ThreeDSLogger, экземпляр которого доступен через статическое поле shared.

Пример:

...
      final class Logger: LogProtocol {

          func log<T>(classMethod: T.Type, tag: String, message: String, exception: (any Error)?) {
              print("\(classMethod), \(tag), \(message), \(exception)")
          }
      }

      ThreeDSLogger.shared.addLogInterface(logger: Logger())
...

По умолчанию используется тег SDK-ThreeDS. Вы можете установить свой собственный, если хотите.

Пример:

...
     ThreeDSLogger.shared.log(classMethod: type(of: self), tag: "My tag", message: "My message", exception: nil)
...

Пример:

...

   ThreeDSLogger.shared.setupLogUploaderConfigProvider(configProvider: ViewController())

...
   extension ViewController: LogUploaderConfigProvider {

      func provideConfig(sdkAppId: String?) -> ThreeDSSDK.LogUploaderConfig? {
        // use the sdkAppId to enable/disable logs or not   
        // enable logs upload
        return .sentry(url: "SentryURL", key: "SentryKey")

        // disable logs upload
        return nil
      }
}
...

Android

Android-интеграция

Подключение библиотеки 3DS2

Необходимо добавить файл библиотеки sdk_threeds-release.aar в папку libs, а затем указать зависимость от добавленной библиотеки.

В версиях SDK <= 2.5.5 добавьте файл sdk_listeners_android.jar в папку libs. Начиная с SDK 2.5.6 нет необходимости добавлять файл sdk_listeners_android.jar.

build.gradle.kts

allprojects {
    repositories {
       // ...
       flatDir {
          dirs("libs")
       }
    }
}

dependencies {
   // dependency for connecting the confirmation functionality via 3DS
   implementation(group = "", name = "sdk_threeds-release", ext = "aar")
   implementation("com.google.code.gson:gson:2.8.5")
   implementation("com.squareup.okhttp3:okhttp:3.11.0")
   implementation("com.google.android.gms:play-services-ads:17.2.1")
   implementation("com.google.android.gms:play-services-location:16.0.0")
}

build.gradle

allprojects {
    repositories {
       // ...
       flatDir {
          dirs 'libs'
       }
    }
}

dependencies {
   // dependency for connecting the confirmation functionality via 3DS
   implementation(group = "", name = "sdk_threeds-release", ext = "aar")
   implementation("com.google.code.gson:gson:2.8.5")
   implementation("com.squareup.okhttp3:okhttp:3.11.0")
   implementation("com.google.android.gms:play-services-ads:17.2.1")
   implementation("com.google.android.gms:play-services-location:16.0.0")
}

Конфигурация Android

Выполнение оплаты с подтверждением через 3DS2

private val factory = Factory()

threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val uiCustomization = factory.newUiCustomization()
threeDS2Service.initialize(
    context,
    configParams,
    "en-US",
    uiCustomization,
    sslContext, // Optional field (needs if you want to pass a custom SSL certificate)
    trustManager, // Optional field (needs if you want to pass a custom SSL certificate)
)

// An example of creating a transaction with custom SSL certificate.
// To create a transaction with a custom certificate, you need to create an SSLContext object and a TrustManager. 
// Then pass it to initialize method of threeDS2Service.
// Both (sslContext and trustManager) parameters must be passed, or neither (they are optional).
//
// threeDS2Service.initialize(
//    context,
//    configParams,
//    "en-US",
//    uiCustomization,
//    sslContext, // Optional field
//    trustManager, // Optional field
// )

val dsRoot: String = "MII346GU349HDE5FH..." //your root-certificate in base64 format
val transaction = threeDS2Service.createTransaction("F000000000", "", "2.1.0", dsRoot)

//  An example of creating a transaction with deviceInfo encryption with a transmitted RSA key.
//  val rsaPem: String = ...
//  val dsRoot: String = ...
//  transaction = threeDS2Service.createTransaction(
//      "",
//      rsaPem,
//      "2.2.0",
//      dsRoot
//   )

//  An example of creating a transaction with deviceInfo encryption with a transmitted EC key.
//  val ecPem: String = ...
//  val directoryServerID: String = ...
//  val dsRoot: String = ...
//  transaction = threeDS2Service.createTransaction(
//      directoryServerID,
//      ecPem,
//      "2.2.0",
//      dsRoot
//   )

// Available data, to be sent to the payment gateway
val authRequestParams = transaction.authenticationRequestParameters!!
val encryptedDeviceInfo: String = authRequestParams.deviceData
val sdkTransactionID: String = authRequestParams.sdkTransactionID
val sdkAppId: String = authRequestParams.sdkAppID
val sdkEphmeralPublicKey: String = authRequestParams.sdkEphemeralPublicKey
val sdkReferenceNumber: String = authRequestParams.sdkReferenceNumber

val challengeParameters = factory.newChallengeParameters()

// Parameters for starting Challenge Flow.
challengeParameters.acsTransactionID =
    paymentOrderSecondStepResponse.threeDSAcsTransactionId
challengeParameters.acsRefNumber = paymentOrderSecondStepResponse.threeDSAcsRefNumber
challengeParameters.acsSignedContent =
    paymentOrderSecondStepResponse.threeDSAcsSignedContent
challengeParameters.set3DSServerTransactionID(paymentOrderResponse.threeDSServerTransId)

// Listener to handle the Challenge Flow execution process.
val challengeStatusReceiver: ChallengeStatusReceiver = object : ChallengeStatusReceiver {

    override fun cancelled() {}

    override fun protocolError(protocolErrorEvent: ProtocolErrorEvent) {}

    override fun runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}

    override fun completed(completionEvent: CompletionEvent) {}

    override fun timedout() {}
}

val timeOut = 5

// Starting Challenge Flow.
transaction.doChallenge(
    activity,
    challengeParameters,
    challengeStatusReceiver,
    timeOut
)

Полный пример кода можно посмотреть в файле net.payrdr.mobile.payment.sample.kotlin.threeds.ThreeDSActivity.

Особенности самотестирования приложения с подключенным 3DS2

При инициализации ThreeDS2Serviceприложение выполняет серию самопроверок. Список с предупреждениями возвращается с помощью метода ThreeDS2Service.getWarnings. Если предупреждений нет, возвращается пустой список.

В перечень проверок входят:

  1. Проверка root-доступа на устройстве (по правилу SW01)
    • Возвращает предупреждение The device is rooted при срабатывании.
  2. Проверка установки приложения только из одобренных магазинов приложений (согласно правилу SW02)

    • Возвращает предупреждение The integrity of the SDK has been tampered при срабатывании.
    • По умолчанию sdk разрешает установку приложения только из Play Market.
    • При необходимости добавить другие маркеты (например, App Gallery) их можно передать в configParams.
    val factory = Factory()
    val threeDS2Service = factory.newThreeDS2Service()
    val configParams = factory.newConfigParameters()
    val trustedAppStores = listOf<String>("com.android.vending", "com.huawei.appmarket")
    
    configParams.removeParam("security", "trustedAppStores")
    configParams.addParam("security", "trustedAppStores", StringUtils.makeString(trustedAppStores))
  3. Проверка несоответствия подписи приложения (по правилу SW02)

    • Возвращает предупреждение The integrity of the SDK has been tampered. при срабатывании.
    • Пример передачи подписи в configParams:
    val factory = Factory()
    val threeDS2Service = factory.newThreeDS2Service()
    val configParams = factory.newConfigParameters()
    val youAppSignature = //signature of your application
    
        configParams.removeParam("security", "appSignature")
    configParams.addParam("security", "appSignature", youAppSignature)
  4. Проверка наличия вредоносных приложений на устройстве (согласно правилу SW02)

    • Возвращает предупреждение The integrity of the SDK has been tampered при срабатывании.
    • По умолчанию запрещены приложения со следующими именами пакетов:
      • de.robv.android.xposed
      • de.robv.android.xposed.installer
      • com.saurik.substrate
    • При необходимости установить собственный список запрещенных приложений, их названия пакетов могут быть переданы в configParams.
    val factory = Factory()
    val threeDS2Service = factory.newThreeDS2Service()
    val configParams = factory.newConfigParameters()
    val maliciousApps = listOf<String>("com.zhiliaoapp.musically", "com.othersapp.harmful")
    
    configParams.removeParam("security", "maliciousApps")
    configParameters.addParam("security", "maliciousApps", StringUtils.makeString(maliciousApps))
  5. Проверка на запуск приложения из-под эмулятора (по правилу SW03)

    • Возвращает предупреждение An emulator is being used to run the App при срабатывании.
  6. Проверка наличия подключенного к приложению отладчика (согласно правилу SW04)

    • Возвращает предупреждение A debugger is attached to the App при срабатывании.
  7. Проверка актуальности версии Android (согласно правилу SW05)

    • Возвращает предупреждение The OS or the OS version is not supportedпри срабатывании.
    • Версии выше API 16 (JELLY BEAN) считаются актуальными (безопасными).

В разделе documentation/threedsвы можете найти дополнительную информацию, описывающую доступные параметры ConfigParameters и UiCustomization для настройки экрана 3DS, а также описание 3DS SDK в части интеграции с серверным приложением.

Пример экрана ввода кода подтверждения:

drawing

Логирование

Внутренние процессы логируются с тегом SDK-ThreeDS. Вы также можете логировать свои процессы. Логирование доступно через класс ThreeDSLogger, экземпляр которого доступен через статическое поле INSTANCE.

...
     ThreeDSLogger.INSTANCE.addLogInterface(object : net.payrdr.mobile.payment.sdk.threeds.LogInterface {
        override fun log(classMethod: Class<*>, tag: String, message: String, p3: Throwable?) {
            Log.i(tag, "$classMethod: $message")
        }
    })
...

По умолчанию используется тег SDK-ThreeDS. Вы можете установить свой собственный, если хотите.

...
     ThreeDSLogger.INSTANCE.log(this.javaClass, "MyTag", "My process", null)
...

Example:

...
    ThreeDSLogger.INSTANCE.setupLogUploaderConfigProvider { sdkAppId ->
        // use the sdkAppId to enable/disable logs or not   
        // enable logs upload
        SentryLogUploaderConfig.Builder()
            .withUrl("SentryURL")
            .withKey("SentryKey")
            .build()
        // disable logs upload
        null
}
...

Заглушка 3DS2

В SDK3DS2 можно использовать заглушку. Экраны SDK зависят от суммы заказа.

Радио-группа

Сумма: 111

Множественный выбор

Сумма: 222

Веб (встроенный HTML)

Сумма: 333

Одноразовый пароль

Сумма: любая другая

Категории:
eCommerce SDK
Категории
Результаты поиска