Идемпотентные потребители веб-хуков в Ruby on Rails для событий Didit (RU)
Создание надежных потребителей веб-хуков критически важно для обработки данных, особенно для событий в реальном времени от платформ верификации личности, таких как Didit.

Обеспечение целостности данныхИдемпотентность жизненно важна для надежной обработки событий веб-хуков, предотвращения дублирующих действий и поддержания согласованного состояния в вашем приложении.
Использование подписей веб-хуковВсегда проверяйте подписи веб-хуков, чтобы подтвердить подлинность и целостность входящих запросов, защищая от подделки и спуфинга.
Использование уникальных идентификаторов событийХраните и проверяйте уникальные идентификаторы событий, предоставляемые в полезных нагрузках веб-хуков, для эффективного обнаружения и отбрасывания дублирующих доставок.
Надежная система веб-хуков DiditDidit предоставляет безопасные, версионированные веб-хуки с HMAC-подписями и уникальными идентификаторами событий, что упрощает реализацию идемпотентных потребителей и обеспечивает надежную доставку событий для критически важных рабочих процессов верификации личности.
Проблема идемпотентности веб-хуков
Веб-хуки — мощный механизм для обмена данными в реальном времени между сервисами, позволяющий вашему приложению мгновенно реагировать на события, происходящие в другой системе. Однако распределенный характер веб-хуков означает, что события иногда могут доставляться несколько раз. Сбои в сети, тайм-ауты или повторные попытки могут привести к дублированию полезных нагрузок веб-хуков. Без надлежащей обработки эти дубликаты могут вызвать значительные проблемы в вашем приложении, такие как создание дублирующихся записей, запуск избыточных действий или повреждение данных.
Именно здесь идемпотентность становится критически важной. Идемпотентная операция — это та, которая дает тот же результат, независимо от того, выполняется ли она один или несколько раз. Для потребителей веб-хуков это означает проектирование вашей системы таким образом, чтобы обрабатывать данное событие только один раз, даже если полезная нагрузка веб-хука получена несколько раз. При работе с конфиденциальными данными, такими как результаты верификации личности от платформ, таких как Didit, обеспечение идемпотентности — это не просто хорошая практика, это необходимо для поддержания целостности данных и надежности системы.
Проверка подписей веб-хуков для безопасности и подлинности
Прежде чем обрабатывать любую полезную нагрузку веб-хука, первым и наиболее важным шагом является проверка ее подлинности. Это гарантирует, что веб-хук действительно исходит от ожидаемого отправителя (например, Didit) и что его содержимое не было изменено при передаче. Веб-хуки Didit, например, включают HMAC-подпись в заголовках запроса, сгенерированную с использованием общего секретного ключа.
В вашем приложении Ruby on Rails вам потребуется получить общий секретный ключ из вашей учетной записи Didit (к которому вы можете получить доступ через Business Console или программно с помощью API). Когда приходит веб-хук, вы вычислите свою собственную HMAC-подпись, используя тело запроса и ваш секретный ключ. Эта вычисленная подпись затем сравнивается с подписью, предоставленной в заголовке веб-хука. Если они не совпадают, запрос должен быть немедленно отклонен.
class DiditWebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
def create
# Retrieve the shared secret key from your environment variables
secret = ENV['DIDIT_WEBHOOK_SECRET']
payload = request.body.read
signature = request.headers['X-Didit-Signature'] # Or similar header name
unless verify_signature(payload, signature, secret)
head :unauthorized
return
end
# Process the webhook payload after verification
process_didit_event(JSON.parse(payload))
head :ok
end
private
def verify_signature(payload, signature, secret)
digest = OpenSSL::Digest.new('sha256')
hmac = OpenSSL::HMAC.hexdigest(digest, secret, payload)
ActiveSupport::SecurityUtils.secure_compare("sha256=#{hmac}", signature)
end
def process_didit_event(event_data)
# ... implementation for processing ...
end
end
Didit упрощает это, предоставляя secret_shared_key как часть своей конфигурации веб-хуков, который может быть получен через API или изменен по мере необходимости. Этот безопасный механизм является фундаментальным для любого рабочего процесса верификации личности, где целостность результатов, таких как результаты проверки ID или Liveness, имеет первостепенное значение.
Реализация идемпотентности с помощью уникальных идентификаторов событий
После того, как вы проверили подлинность веб-хука, следующим шагом является обеспечение идемпотентности. Большинство хорошо спроектированных систем веб-хуков, включая Didit, предоставляют уникальный идентификатор для каждого события. Этот ID имеет решающее значение для обнаружения и предотвращения дублирующей обработки. Для веб-хуков Didit (особенно версии 3, которая рекомендуется) каждая полезная нагрузка события включает уникальный ID, который вы можете использовать для этой цели.
Стратегия заключается в хранении этих ID событий в вашей базе данных и проверке их перед обработкой. Обычный шаблон включает создание модели EventLog или WebhookEvent:
# db/migrate/YYYYMMDDHHMMSS_create_webhook_events.rb
class CreateWebhookEvents < ActiveRecord::Migration[7.x]
def change
create_table :webhook_events do |t|
t.string :event_id, null: false, index: { unique: true }
t.string :event_type
t.jsonb :payload
t.string :status, default: 'pending'
t.timestamps
end
end
end
Когда приходит веб-хук:
- Извлеките уникальный
event_idиз полезной нагрузки. - Попытайтесь создать новую запись
WebhookEventс этимevent_id. - Если создание не удается из-за нарушения уникального ограничения (что означает, что
event_idуже существует), то вы знаете, что это дубликат, и можете безопасно игнорировать его или регистрировать как таковой. - Если создание успешно, перейдите к обработке события, соответствующим образом помечая его статус.
class DiditWebhooksController < ApplicationController
# ... (signature verification as above) ...
def create
# ... (signature verification) ...
event_data = JSON.parse(payload)
event_id = event_data['id'] # Assuming 'id' is the unique event identifier from Didit
# Use a transaction to ensure atomicity
ActiveRecord::Base.transaction do
webhook_event = WebhookEvent.find_or_initialize_by(event_id: event_id)
if webhook_event.persisted? # If it already exists, it's a duplicate
Rails.logger.info "Duplicate webhook event received: #{event_id}"
head :ok
return
end
webhook_event.event_type = event_data['type']
webhook_event.payload = event_data
webhook_event.status = 'processing'
webhook_event.save!
# Process the event in a background job for long-running tasks
DiditEventProcessorJob.perform_later(webhook_event.id)
head :ok
end
rescue ActiveRecord::RecordNotUnique # Handle race conditions for event_id
Rails.logger.warn "Race condition detected for webhook event: #{event_id}. Ignoring."
head :ok
rescue JSON::ParserError
head :bad_request
rescue => e
Rails.logger.error "Error processing webhook: #{e.message}"
head :internal_server_error
end
end
Этот подход, в сочетании с фоновыми заданиями для фактической обработки, гарантирует, что ваш конечный пункт веб-хука быстро реагирует, предотвращая повторные попытки от отправителя, одновременно надежно обрабатывая дубликаты.
Обработка состояний гонки и транзакций
Даже при наличии уникального индекса могут возникать состояния гонки, если два идентичных веб-хука приходят почти одновременно. Оба могут попытаться создать новую запись WebhookEvent до того, как первая зафиксирует свою транзакцию. Чтобы смягчить это:
- Используйте транзакции базы данных: Оберните логику
find_or_initialize_byи последующей обработки в транзакцию базы данных. Это гарантирует, что либо вся операция будет успешной, либо завершится неудачей, поддерживая согласованность данных. - Обработка
RecordNotUnique: Будьте готовы перехватывать исключенияActiveRecord::RecordNotUnique. Если это исключение возникает при попытке сохранить новыйWebhookEvent, это означает состояние гонки, когда другой процесс уже вставил событие, и вы можете безопасно рассматривать его как дубликат.
Для операций, изменяющих основные данные приложения, расширение транзакции для охвата этих изменений имеет решающее значение, или, по крайней мере, обеспечение того, чтобы фоновое задание, обрабатывающее событие, также реализовывало свои собственные проверки идемпотентности для данных приложения, которые оно изменяет.
Как Didit помогает
Didit — это платформа идентификации, ориентированная на разработчиков, с искусственным интеллектом, разработанная с учетом надежности и безопасности, что упрощает реализацию надежных потребителей веб-хуков. Наша модульная архитектура предоставляет чистые API и безопасные веб-хуки, которые изначально предназначены для поддержки идемпотентной обработки.
- Безопасные веб-хуки: Веб-хуки Didit предоставляют надежные HMAC-подписи (используя
secret_shared_key, которым вы можете управлять и обновлять) для обеспечения подлинности и целостности каждого события. Этот важный первый шаг в идемпотентности встроен. Вы даже можете указатьwebhook_version(рекомендуется v3) для оптимальной структуры полезной нагрузки. - Уникальные идентификаторы событий: Каждое событие веб-хука Didit включает уникальный идентификатор, что упрощает реализацию логики дедупликации, обсуждаемой выше.
- Настраиваемое хранение данных: С Didit вы контролируете, как долго хранятся данные верификации. Вы можете установить политики хранения данных от 1 месяца до 10 лет или даже null для неограниченного срока, непосредственно в Business Console или через API. Это позволяет вам соблюдать нормативные требования (например, GDPR), управляя при этом объемом ваших данных. Это также связано с тем, как ваш потребитель веб-хуков может хранить и управлять журналами событий.
- Бесплатный базовый KYC и модульный дизайн: Didit предлагает бесплатный базовый KYC, позволяя вам начать создавать и тестировать ваших потребителей веб-хуков без предоплаты. Наш модульный дизайн означает, что вы можете легко интегрировать конкретные продукты верификации личности — такие как ID Verification для проверки документов, Passive & Active Liveness для предотвращения мошенничества или Age Estimation для проверки возраста — и получать обновления в реальном времени через веб-хуки.
Используя надежную и безопасную систему веб-хуков Didit, разработчики могут больше сосредоточиться на основной логике своего приложения и меньше на сложностях защиты и дедупликации входящих событий, что приводит к более устойчивым и надежным рабочим процессам верификации личности.
Готовы начать?
Готовы увидеть Didit в действии? Получите бесплатную демонстрацию сегодня.
Начните бесплатно проверять личности с помощью бесплатного уровня Didit.