Процесс оплаты 3DS2 SDK
На приведенной ниже диаграмме показан процесс оплаты 3DS2 SDK.
Имейте в виду, что ACS многих эмитентов неправильно работают с 3DS Mobile SDK.
- Клиент создает заказ.
- Мобильный сервер регистрирует этот заказ в платежном шлюзе через register.do.
- Мобильный сервер получает в ответе уникальный номер заказа
mdOrder
. - Клиент заполняет платежные данные.
- Мобильное приложение отправляет платежные данные на сервер.
- Мобильный сервер использует эти платежные данные для совершения платежа через paymentorder.do.
- Передайте
threeDSSDK=true
, чтобы указать, что следует использовать 3DS2 SDK.
- Передайте
- Мобильный сервер получает ответ без ключей ACS. Это означает, что оплата завершена и нам нужно перейти к Шагу 22.
- Мобильный сервер получает ответ с ключами ACS.
- Ответ должен содержать
threeDSServerTransId
иthreeDSSDKKey
- Ответ не должен содержать
threeDSMethodURL
, который используется в случае перенаправления через браузер на ACS.
- Ответ должен содержать
- Мобильный сервер отправляет данные 3DS2 SDK в мобильное приложение
- Мобильное приложение инициирует 3DS2 SDK с помощью метода
createTransaction
.-
directoryServerID
зависит от платежной системы (для тестов можно использовать A000000003) -
messageVersion
на данный момент 2.1.0 -
pemPublicKey
для Android и iOS – это сертификат pem, полученный в ответ вthreeDSSDKKey
на Шаге 10 -
dsRoot
для Android и iOS зависит от платежной системы. Скачать тестовый ключ
-
- 3DS2 SDK собирает данные устройства и шифрует их.
- Мобильное приложение отправляет зашифрованные данные устройства на мобильный сервер
- Мобильный сервер инициирует второй вызов платежного 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.
-
- Платежный шлюз возвращает новые специальные параметры для 3DS2 SDK.
- Мобильный сервер отправляет эти параметры в мобильное приложение.
- Мобильное приложение инициирует поток прохождения проверки с помощью метода
doChallenge
.- Параметр doChallenge
acsTransactionID
соответствуетthreeDSAcsTransactionId
в ответе платежного шлюза - Параметр doChallenge
acsRefNumber
соответствует параметруthreeDSAcsRefNumber
в ответе платежного шлюза - Параметр doChallenge
acsSignedContent
соответствует параметруthreeDSAcsSignedContent
в ответе платежного шлюза - Параметр doChallenge
3DSServerTransactionID
соответствуетthreeDSServerTransId
в ответе платежного шлюза
- Параметр doChallenge
- 3DS2 SDK связывается с ACS эмитентов через CReq/CRes API до тех пор, пока Клиент не подтвердит свой платеж.
- ACS отправляет RReq платежному шлюзу для подтверждения или отклонения платежа.
- 3DS2 SDK информирует мобильное приложение о завершении потока 3DS2 через
ChallengeStatusReceiver
. - Мобильный сервер завершает платеж с помощью finish3dsVer2Payment.do
- Платежный шлюз осуществляет платеж.
- Платежный шлюз отправляет уведомление обратного вызова на сервер продавца, если оно настроено для продавца.
- Мобильный сервер проверяет окончательный статус платежа через getOrderStatusExtended.do.
- Мобильное приложение показывает результат платежа клиенту.
IOS
iOS-интеграция
Интеграция ThreeDS SDK
-
Скачайте последнюю версию фреймворка и добавьте
ThreeDSSDK.xcframework
в проект;
- Отметьте ThreeDSSDK.xcframework как
Embed & Sign
вtagret -> general
;
Конфигурация 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
.
- Для добавления log-интерфейсов необходимо вызвать
ThreeDSLogger
-методaddLogInterface()
.
Пример:
...
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
. Вы можете установить свой собственный, если хотите.
- Для логирования собственных событий необходимо вызвать
Logger
-методlog()
.
Пример:
...
ThreeDSLogger.shared.log(classMethod: type(of: self), tag: "My tag", message: "My message", exception: nil)
...
- Вы можете загрузить логи для конкретного
sdkAppId
. При этом необходимо выполнить требования протоколаLogUploaderConfigProvider
и настроить ThreeDSLogger. В настоящий момент доступен толькоSentry
.
Пример:
...
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
. Если предупреждений нет, возвращается пустой список.
В перечень проверок входят:
- Проверка root-доступа на устройстве (по правилу
SW01
)- Возвращает предупреждение
The device is rooted
при срабатывании.
- Возвращает предупреждение
-
Проверка установки приложения только из одобренных магазинов приложений (согласно правилу
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))
- Возвращает предупреждение
-
Проверка несоответствия подписи приложения (по правилу
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)
- Возвращает предупреждение
-
Проверка наличия вредоносных приложений на устройстве (согласно правилу
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))
- Возвращает предупреждение
-
Проверка на запуск приложения из-под эмулятора (по правилу
SW03
)- Возвращает предупреждение
An emulator is being used to run the App
при срабатывании.
- Возвращает предупреждение
-
Проверка наличия подключенного к приложению отладчика (согласно правилу
SW04
)- Возвращает предупреждение
A debugger is attached to the App
при срабатывании.
- Возвращает предупреждение
-
Проверка актуальности версии Android (согласно правилу
SW05
)- Возвращает предупреждение
The OS or the OS version is not supported
при срабатывании. - Версии выше API 16 (JELLY BEAN) считаются актуальными (безопасными).
- Возвращает предупреждение
В разделе documentation/threeds
вы можете найти дополнительную информацию, описывающую доступные параметры ConfigParameters
и UiCustomization
для настройки экрана 3DS, а также описание 3DS SDK в части интеграции с серверным приложением.
Пример экрана ввода кода подтверждения:
Логирование
Внутренние процессы логируются с тегом SDK-ThreeDS
. Вы также можете логировать свои процессы.
Логирование доступно через класс ThreeDSLogger
, экземпляр которого доступен через статическое поле INSTANCE
.
-
Для добавления log- интерфейсов необходимо вызвать
ThreeDSLogger
-методaddLogInterface()
.Пример для логирования в LogCat:
...
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
. Вы можете установить свой собственный, если хотите.
-
Для регистрации собственных событий необходимо вызвать
Logger
-методlog()
.Пример:
...
ThreeDSLogger.INSTANCE.log(this.javaClass, "MyTag", "My process", null)
...
- Вы можете загрузить логи для конкретного
sdkAppId
. При этом необходимо настроить LogUploaderConfigProvider ля ThreeDSLogger. В настоящий момент доступен толькоSentry
.
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
Одноразовый пароль
Сумма: любая другая