Интеграция платежной системы Vipps
Студент добавит альтернативный способ оплаты через популярную систему Vipps, работая с внешними API, и изучит концепцию вебхуков.
Введение в интеграцию альтернативных платежных систем
На прошлом уроке мы успешно интегрировали Stripe. Однако современные интернет-магазины часто требуют подключения локальных или специфических платежных решений, таких как Vipps (популярная система в скандинавских странах). Интеграция нескольких платежных шлюзов требует правильной архитектуры. Мы будем использовать принцип проектирования, основанный на интерфейсах (Direct Instruction). Это позволит нашему приложению легко переключаться между Stripe и Vipps без переписывания основной логики оформления заказа. В этом уроке мы изучим работу с REST API внешних сервисов, аутентификацию по API-ключам и обработку асинхронных ответов через вебхуки (Webhooks).
Вебхук — это механизм получения уведомлений от сторонних сервисов в реальном времени. Когда пользователь оплачивает заказ в приложении Vipps на своем телефоне, сервер Vipps отправляет HTTP POST запрос на специальный URL (вебхук) нашего магазина, сообщая, что статус платежа изменился. Это критически важно, так как пользователь может закрыть браузер до перенаправления на страницу успешной оплаты, и вебхук гарантирует, что мы зафиксируем оплату.
<?php
namespace App\Services\Payment;
// Определяем единый контракт для всех платежных систем
interface PaymentGateway {
public function pay(float $amount, string $orderId): bool;
}
class VippsGateway implements PaymentGateway {
private string $clientId;
private string $clientSecret;
private string $merchantSerialNumber;
public function __construct() {
$this->clientId = env('VIPPS_CLIENT_ID');
$this->clientSecret = env('VIPPS_CLIENT_SECRET');
$this->merchantSerialNumber = env('VIPPS_MERCHANT_SERIAL_NUMBER');
}
public function pay(float $amount, string $orderId): bool {
// Логика формирования запроса к REST API Vipps
// 1. Получение Access Token
// 2. Инициация платежа (Payment Intent)
// В рамках данного примера возвращаем true для симуляции
return true;
}
}
Архитектура взаимодействия с API
Разберем процесс шаг за шагом (Scaffolding). Интеграция с API Vipps состоит из нескольких этапов. Во-первых, аутентификация. Большинство банковских API используют стандарт OAuth 2.0. Наше приложение должно отправить `client_id` и `client_secret` на сервер авторизации Vipps, чтобы получить временный токен доступа (Access Token). Во-вторых, инициация платежа. Мы отправляем POST-запрос с деталями заказа (сумма, валюта, номер телефона пользователя, если известен) и получаем взамен URL, на который нужно перенаправить пользователя для подтверждения оплаты.
Типичная ошибка новичков — хранение ключей API прямо в коде. Как вы можете видеть в примере выше, мы используем функцию `env()`, которая читает конфигурацию из файла `.env`. Это гарантирует, что секретные ключи не попадут в систему контроля версий Git и не будут скомпрометированы.
Задание
Настройка локального тестирования вебхуков
- Зарегистрируйте аккаунт разработчика на портале Vipps (или используйте тестовые ключи).
- Добавьте ключи VIPPS_CLIENT_ID и VIPPS_CLIENT_SECRET в ваш файл .env.
- Скачайте и установите утилиту Ngrok для проброса локального порта в интернет.
- Запустите команду 'ngrok http 8000' в терминале.
- Скопируйте сгенерированный HTTPS URL и укажите его в настройках вебхуков в панели Vipps (например, https://your-ngrok-url.com/api/webhooks/vipps).
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Order;
use Illuminate\Support\Facades\Log;
class VippsWebhookController extends Controller {
public function handle(Request $request) {
// Логируем входящий запрос для отладки
Log::info('Vipps Webhook Received', $request->all());
$orderId = $request->input('orderId');
$status = $request->input('transactionInfo.status');
$order = Order::find($orderId);
if (!$order) {
return response()->json(['error' => 'Order not found'], 404);
}
if ($status === 'RESERVED' || $status === 'SALE') {
$order->status = 'paid';
$order->save();
}
// Обязательно возвращаем 200 OK, чтобы Vipps понял, что мы приняли вебхук
return response()->json(['status' => 'success'], 200);
}
}
Обработка вебхуков и безопасность
В коде выше представлен контроллер для обработки вебхуков. Важно понимать, что маршрут для этого контроллера должен находиться в файле `routes/api.php`, а не `web.php`. Маршруты в `web.php` по умолчанию защищены middleware `VerifyCsrfToken`, который блокирует POST-запросы без специального скрытого токена. Сторонний сервер (Vipps) не знает ваш CSRF-токен, поэтому запрос будет отклонен с ошибкой 419. Размещение маршрута в `api.php` отключает проверку CSRF.
Для обеспечения безопасности (Mastery Learning) мы должны проверять подпись запроса. Vipps присылает специальные заголовки (headers), которые мы должны расшифровать с помощью нашего секретного ключа, чтобы убедиться, что запрос действительно пришел от Vipps, а не от злоумышленника, пытающегося подделать статус заказа на 'paid'.