Reviewed-on: #2
Alfa Bank SDK (Unofficial)
Профессиональная PHP-библиотека для интеграции с API Альфа-Банка (BaaS и СБП). Построена на базе Saloon v3 и Spatie Laravel Data.
Требования
- PHP 8.2+
- Saloon v3.0+
- Spatie Laravel Data
Установка
composer require apoloz/alfa-bank-sdk
Подготовка сертификатов (mTLS)
Взаимодействие с API Альфа-Банка требует двухстороннего TLS-соединения. Банк не выдает закрытый ключ, вы должны сгенерировать его самостоятельно.
1. Генерация закрытого ключа и запроса (CSR):
Используйте OpenSSL для создания ключа и файла запроса. Создайте файл openssl.cnf:
[req]
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
C = RU
L = Moscow
O = Название Вашей Компании
CN = ФИО Ответственного
emailAddress = your_email@company.com
1.2.643.100.4 = 1234567890 (Ваш ИНН)
Выполните команды в терминале:
# Генерация закрытого ключа (храните его в секрете!)
openssl genrsa -out private.key 2048
# Генерация запроса на сертификат
openssl req -new -key private.key -out request.csr -config openssl.cnf -utf8
2. Отправка в Банк:
Отправьте файл request.csr на почту alfa_api@alfabank.ru. В ответ банк пришлет публичный сертификат (client.cer или client.crt).
3. Использование:
Поместите полученный сертификат и ваш закрытый ключ в надежное место и укажите пути к ним в .env (переменные ALFA_BAAS_CERT_PATH и ALFA_BAAS_KEY_PATH).
Конфигурация (Laravel)
Опубликуйте файл конфигурации:
php artisan vendor:publish --tag=alfa-bank-config
Настройка .env
Добавьте следующие переменные в ваш файл .env. Вам понадобятся сертификаты (PEM) и ключи.
# --- BaaS (Номинальные счета, Выплаты) ---
ALFA_BAAS_ENVIRONMENT=sandbox # или production
ALFA_BAAS_CLIENT_ID=your-client-id
ALFA_BAAS_CLIENT_SECRET=your-client-secret
# URL в вашем приложении, на который вернется пользователь после входа (должен совпадать с настройками в Портале)
ALFA_BAAS_REDIRECT_URI=https://your-app.com/alfa/callback
ALFA_BAAS_CERT_PATH=storage/certs/baas_cert.pem
ALFA_BAAS_KEY_PATH=storage/certs/baas_key.pem
# Путь к корневым сертификатам (или 'false' для отключения проверки SSL в sandbox)
ALFA_BAAS_CA_BUNDLE=false
# Опционально: Ключи для CMS-подписи (если отличаются от транспортных)
# ALFA_BAAS_SIGNING_CERT_PATH=storage/certs/sign_cert.pem
# ALFA_BAAS_SIGNING_KEY_PATH=storage/certs/sign_key.pem
# --- SBP (СБП, QR-коды) ---
ALFA_SBP_ENVIRONMENT=sandbox # или production
ALFA_SBP_ALIAS=your-key-name-alias
ALFA_SBP_CERT_PATH=storage/certs/sbp_cert.pem
ALFA_SBP_KEY_PATH=storage/certs/sbp_key.pem
ALFA_SBP_CA_BUNDLE=false
# --- Webhooks ---
ALFA_WEBHOOK_USER=alfa
ALFA_WEBHOOK_PASSWORD=secret
# Для проверки JWS-подписи вебхуков (опционально)
ALFA_WEBHOOK_PUBLIC_KEY=storage/certs/alfa_public_key.pem
Файл конфигурации (config/alfa-bank.php)
Вот как выглядит структура конфигурационного файла по умолчанию. Вы можете использовать его для тонкой настройки, например, чтобы задать пути динамически.
return [
'baas' => [
'environment' => env('ALFA_BAAS_ENVIRONMENT', 'sandbox'),
'client_id' => env('ALFA_BAAS_CLIENT_ID'),
'client_secret' => env('ALFA_BAAS_CLIENT_SECRET'),
'redirect_uri' => env('ALFA_BAAS_REDIRECT_URI'),
'certificate_path' => env('ALFA_BAAS_CERT_PATH'),
'private_key_path' => env('ALFA_BAAS_KEY_PATH'),
'ca_bundle' => env('ALFA_BAAS_CA_BUNDLE'),
// ...
],
'sbp' => [
'environment' => env('ALFA_SBP_ENVIRONMENT', 'sandbox'),
'key_name_alias' => env('ALFA_SBP_ALIAS'),
'certificate_path' => env('ALFA_SBP_CERT_PATH'),
'private_key_path' => env('ALFA_SBP_KEY_PATH'),
'ca_bundle' => env('ALFA_SBP_CA_BUNDLE'),
// ...
],
'webhook' => [
'user' => env('ALFA_WEBHOOK_USER'),
'password' => env('ALFA_WEBHOOK_PASSWORD'),
'alfa_public_key' => env('ALFA_WEBHOOK_PUBLIC_KEY'),
],
];
Подключение и Безопасность
SDK поддерживает две разные модели безопасности, используемые в API Альфа-Банка.
1. Подключение к СБП (Pay-in)
Шаги для получения доступа:
- Генерируете пару ключей:
openssl req -x509 -newkey rsa:2048 -keyout client.key -out client.crt -nodes -days 3650. - Отправляете
client.crtменеджеру банка (acquiring@alfabank.ru). - Получаете от банка
alias(key-name) иTermNo.
Поток данных и подпись:
- Transport: Обязательный MTLS. Вы должны передать
client.crtиclient.keyв конфигурацию Guzzle/Saloon. - Payload: Тело запроса канонизируется по алгоритму JCS.
- Signature: SHA256withRSA подпись JCS-строки помещается в заголовок
Authorization.
SDK делает это автоматически:
// В config/alfa-bank.php
'sbp' => [
'alias' => 'my-company-alias',
'private_key' => storage_path('certs/client.key'),
'cert' => storage_path('certs/client.crt'),
],
2. Подключение к BaaS (Номинальные счета)
Шаги для получения доступа:
- Регистрация в личном кабинете партнера.
- Получение
client_idиclient_secretдля OAuth2. - Регистрация публичного ключа для проверки подписей выплат.
Поток данных и подпись:
- Auth: Стандартный OAuth2 Bearer Token.
- Payload Signature: Для критических операций (выплаты, идентификация) требуется
digestSignatures. Это массив CMS-подписей (PKCS7) в формате Base64, которыми подписываются финансовые поля.
Пример формирования CMS в SDK:
use Apoloz\AlfaBank\Utils\CmsSigner;
$payload = json_encode($dataToSign);
$signature = CmsSigner::sign($payload, $privateKey, $certificate);
// $signature помещается в массив digestSignatures
3. Авторизация Authorization Code Flow (H2H)
SDK использует нативный функционал Saloon для OAuth2.
1. Инициализация:
$baas = AlfaBank::baas(
clientId: '...', clientSecret: '...', redirectUri: '...',
certificatePath: '...', privateKeyPath: '...'
);
2. Получение ссылки на вход:
$url = $baas->getAuthorizationUrl(['beneficiaries']);
// Перенаправьте пользователя на $url
3. Обмен кода на токен:
$authenticator = $baas->getAccessToken($code);
$baas->authenticate($authenticator); // Применить токен
// Сохраните $authenticator->getRefreshToken() в БД
4. Обновление токена:
$newAuth = $baas->refreshAccessToken($savedRefreshToken);
$baas->authenticate($newAuth);
Пример обработки callback в Laravel:
// routes/web.php
Route::get('/alfa/callback', function (Request $request, AlfaBankConnector $baas) {
$code = $request->query('code');
// Обмениваем временный код на постоянные токены
$authenticator = $baas->getAccessToken($code);
// Сохраняем refresh_token в БД для будущих обновлений сессии
$refreshToken = $authenticator->getRefreshToken();
auth()->user()->update(['alfa_refresh_token' => $refreshToken]);
return "Авторизация в Альфа-Банке прошла успешно!";
});
Полный пример: examples/13_h2h_auth_service.php
4. Генерация Client Secret (Утилита)
Если банк выдал только сертификаты, вы можете сгенерировать client_secret самостоятельно:
// См. examples/14_generate_client_secret.php
$baas->send(new RefreshClientSecretRequest($clientId));
Важно для продакшена: Запрос нового секрета инвалидирует старый. Если у вас запущено несколько экземпляров приложения (или worker-ов), не запрашивайте секрет при каждом старте. Решение: Получите секрет один раз, сохраните в общий кеш (Redis/DB) с TTL (например, 29 дней) и запрашивайте новый только при истечении срока или отсутствии в кеше. Полный пример автоматизации: examples/16_automated_startup.php
Архитектура и Потоки данных
Гибридный поток: СБП -> Номинальный счет
sequenceDiagram
participant Client as Покупатель
participant SBP as SDK (SBP Connector)
participant API as Alfa Bank API
participant BaaS as SDK (BaaS Connector)
Note over SBP, API: MTLS + JCS Signature
SBP->>API: 1. GetQrCodeRequest(NominalAcc)
API-->>SBP: 2. QR Payload (URL)
Client->>API: 3. Оплата в приложении (СБП)
Note over API, BaaS: Webhook with Signature
API->>BaaS: 4. Webhook (Входящий платеж)
Note over BaaS, API: OAuth2 + CMS Signature
BaaS->>API: 5. IdentifyTransactionRequest(beneficiaryId)
API-->>BaaS: 6. 200 OK (Зачислено)
Примеры использования
1. СБП: Прием платежа на номинальный счет
use Apoloz\AlfaBank\Laravel\Facades\Sbp;
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
$response = Sbp::send(new GetQrCodeRequest(
new QrCodeRequestData(
termNo: '90080567',
amount: '10000', // 100.00 RUB
paymentPurpose: 'Пополнение кошелька #123'
)
));
echo "QR URL: " . $response->dto()->payload;
2. Идентификация платежа (BaaS)
Когда платеж пришел на номинальный счет, его нужно привязать к бенефициару:
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
$data = new IdentifyRequestData(
transactionId: '1220112MOCO#DS4001415',
accountNumber: '40702810...',
amountDistribution: AmountDistributionData::collect([
['beneficiaryId' => 'BEN-001', 'amount' => '100.00']
], DataCollection::class)
);
// Автоматическая подпись данных (использует сертификаты из конфигурации)
$data->sign($baas->getSigner());
AlfaBank::send(new IdentifyTransactionRequest($data));
3. Работа с номинальными счетами (Бенефициары)
... (existing content) ...
4. Самозанятые (Регистрация доходов)
use Apoloz\AlfaBank\Requests\SelfEmployed\RegisterIncomeRequest;
use Apoloz\AlfaBank\Data\SelfEmployed\CreateIncomeRequestData;
$data = new CreateIncomeRequestData(
vatin: '1234567890',
name: 'Консультационные услуги',
amount: '5000.00',
date: now()->format('Y-m-d')
);
$response = AlfaBank::send(new RegisterIncomeRequest($data));
5. Файловый обмен (KYC)
Загрузка сканов документов бенефициаров через pre-signed ссылки:
use Apoloz\AlfaBank\Requests\Files\UploadFileRequest;
$file = fopen('document.pdf', 'r');
$uploadUrl = 'https://baas.alfabank.ru/filebox/...'; // Получено из метода создания бенефициара
AlfaBank::send(new UploadFileRequest($uploadUrl, $file));
Сценарии для Laravel Tinker (Copy-Paste)
Эти примеры разработаны специально для быстрого запуска и тестирования в консоли php artisan tinker. Они содержат полные цепочки бизнес-логики.
- 17_laravel_tinker_scoring_creation.php — Скоринг и Создание Бенефициара: Полный цикл проверки и регистрации контрагента с автоматической подписью данных.
- 18_laravel_tinker_identification_payout.php — Идентификация и Выплата: Привязка входящих денег к бенефициару и последующий вывод на карту (с шифрованием PAN).
- 19_laravel_tinker_card_registration_payout.php — Безопасная регистрация карт: Токенизация карты (создание Реквизита) и выплата по ID (PCI DSS Friendly).
Продвинутые возможности
Управление возвратами СБП
Просмотр всей истории попыток возврата по транзакции:
$response = Sbp::send(new GetQrcReversalHistoryRequest($payrrn, $termNo));
foreach ($response->dto()->refunds as $refund) {
echo "Статус возврата: " . $refund->status;
}
Webhook Handling (Laravel)
// Обработка СБП уведомлений в Listener
public function handle(AlfaWebhookReceived $event) {
if ($event->webhook->isSbp()) {
$data = Sbp::parsePaymentNotification($event->webhook->payload);
Log::info("СБП Оплата: {$data->amount} коп.");
}
}