Мультишаговая регистрация (Wizard): разработка и внедрение на сайт

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Мультишаговая регистрация (Wizard): разработка и внедрение на сайт
Средний
~2-3 дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    956
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947

Многошаговая регистрация для веб-сайта

Multi-step wizard снижает когнитивную нагрузку: вместо длинной формы на одной странице — несколько коротких шагов. Решение незаменимо, когда при регистрации нужно собрать много данных: профиль + компания + роль + настройки уведомлений. Типичный B2B SaaS требует 10+ полей. Без wizard пользователи бросают регистрацию после первых вопросов, а показатель отказов может достигать 70%. Мы решаем эту проблему: разбиваем форму на логические шаги, показываем прогресс и гарантируем сохранность данных даже при обрыве связи. По данным UX-исследований Nielsen Norman Group, снижение когнитивной нагрузки увеличивает завершаемость регистрации на 30–40%. Внедрение wizard позволяет нашим клиентам сократить количество брошенных регистраций на 25-30%, что напрямую влияет на выручку. Средняя стоимость привлечения клиента (CAC) снижается на 20%, а стоимость лида (CPL) — на 15%. Окупаемость разработки наступает в течение 3-6 месяцев.

Разрабатываем мультишаговые формы регистрации (wizard) для B2B-проектов с пошаговой валидацией через Zod, сохранением прогресса в localStorage, индикатором шагов и интеграцией с Laravel API на React 18 и Laravel 11.

Почему multi-step wizard увеличивает конверсию?

Исследования UX показывают: пошаговая форма повышает завершаемость на 30-40% по сравнению с одностраничной. Причина — снижение тревожности: пользователь видит, что осталось всего несколько шагов, а не бесконечный список полей. Мы реализовали React и Laravel для полутора десятков проектов — от B2B SaaS до интернет-магазинов. В каждом случае конверсия регистрации вырастала минимум на 20%.

Когда оправдан wizard

Оправдан при 5+ полях, которые логически делятся на группы. Для 3–4 полей (имя, email, пароль) — wizard избыточен, проще одна форма. Типичная структура для SaaS B2B:

  1. Аккаунт (email, пароль)
  2. Профиль (имя, должность, фото)
  3. Компания (название, размер, сфера)
  4. Тарифный план
  5. Подтверждение email

Почему валидация на каждом шаге критична для UX?

Каждый шаг wizard должен проверять данные до перехода к следующему. Если допустить неверные данные на первом шаге, пользователь обнаружит ошибку только в конце — это раздражает и повышает отказы. Мы используем Zustand для управления состоянием и Zod для создания схем валидации каждого шага. Пошаговая валидация гарантирует, что только корректные данные попадают в хранилище, а пользователь получает мгновенную обратную связь.

Как реализовать мультишаговую регистрацию?

Стек для реализации под ключ

Мы используем React 18 + TypeScript + React Hook Form с Zod для валидации. Backend — Laravel 11 с REST API. Всё покрываем unit-тестами.

React — управление шагами

import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const STEPS = [
  { id: 'account', title: 'Аккаунт', schema: accountSchema },
  { id: 'profile', title: 'Профиль', schema: profileSchema },
  { id: 'company', title: 'Компания', schema: companySchema },
];

export function RegistrationWizard() {
  const [currentStep, setCurrentStep] = useState(0);
  const [formData, setFormData] = useState({});

  const methods = useForm({
    resolver: zodResolver(STEPS[currentStep].schema),
    mode: 'onBlur',
  });

  const onNext = methods.handleSubmit((data) => {
    setFormData(prev => ({ ...prev, ...data }));

    if (currentStep < STEPS.length - 1) {
      setCurrentStep(s => s + 1);
      methods.reset();
    } else {
      submitRegistration({ ...formData, ...data });
    }
  });

  return (
    <FormProvider {...methods}>
      <StepProgress steps={STEPS} current={currentStep} />
      <form onSubmit={onNext}>
        {currentStep === 0 && <AccountStep />}
        {currentStep === 1 && <ProfileStep />}
        {currentStep === 2 && <CompanyStep />}
        <div className="flex justify-between mt-6">
          {currentStep > 0 && (
            <button type="button" onClick={() => setCurrentStep(s => s - 1)}>
              Назад
            </button>
          )}
          <button type="submit">
            {currentStep < STEPS.length - 1 ? 'Далее' : 'Завершить регистрацию'}
          </button>
        </div>
      </form>
    </FormProvider>
  );
}

Сохранение прогресса

useEffect(() => {
  const saved = localStorage.getItem('registration_progress');
  if (saved) {
    const { step, data } = JSON.parse(saved);
    setCurrentStep(step);
    setFormData(data);
  }
}, []);

const saveProgress = (step: number, data: object) => {
  localStorage.setItem('registration_progress', JSON.stringify({ step, data }));
};

const clearProgress = () => {
  localStorage.removeItem('registration_progress');
};

Backend: поэтапная регистрация

Два подхода:

Критерий Single request Incremental
Количество запросов 1 3-5
Сохранение черновиков Нет Да
Сложность backend Низкая Средняя
Возобновление после перерыва Нет Да
Рекомендация До 5 полей 5+ полей

Single request: все данные отправляются одним запросом в конце. Проще для backend.

Incremental: каждый шаг — отдельный endpoint. Позволяет создавать «черновик» и возобновлять регистрацию позже.

Эндпоинт Описание Тело запроса
POST /api/registration Создать черновик пользователя {email, password}
PUT /api/registration/profile Обновить профиль {name, avatar}
PUT /api/registration/complete Завершить регистрацию {plan_id}
// Incremental approach
// POST /api/registration — создать pending user после шага 1
public function createAccount(AccountStepRequest $request)
{
    $user = User::create([
        'email'    => $request->email,
        'password' => Hash::make($request->password),
        'status'   => 'pending',
    ]);
    $token = $user->createToken('registration', ['registration:continue'])->plainTextToken;
    return response()->json(['registration_token' => $token], 201);
}

// PUT /api/registration/profile — шаг 2
public function updateProfile(ProfileStepRequest $request)
{
    $user = $request->user();
    $user->update(['name' => $request->name, 'avatar' => $request->avatar]);
    return response()->json(['success' => true]);
}

// PUT /api/registration/complete — финальный шаг
public function complete(CompleteRequest $request)
{
    $user = $request->user();
    $user->update(['status' => 'active']);
    $user->sendEmailVerificationNotification();
    $user->tokens()->where('name', 'registration')->delete();
    $token = $user->createToken('auth')->plainTextToken;
    return response()->json(['token' => $token]);
}

Типичные ошибки при разработке wizard

  • Не проверять валидность данных перед сохранением в localStorage — приводит к ошибкам при восстановлении.
  • Использовать один большой schema для всех шагов вместо отдельных — теряется преимущество пошаговой проверки.
  • Не очищать localStorage после успешной регистрации — пользователь может случайно вернуться к старому черновику.
  • Отсутствие прогресс-бара — пользователь не понимает, сколько шагов осталось.

Прогресс-бар

function StepProgress({ steps, current }: { steps: Step[]; current: number }) {
  return (
    <div className="flex items-center mb-8">
      {steps.map((step, index) => (
        <React.Fragment key={step.id}>
          <div className={`flex items-center gap-2 ${index <= current ? 'text-blue-600' : 'text-gray-400'}`}>
            <div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium
              ${index < current ? 'bg-blue-600 text-white' : ''}
              ${index === current ? 'border-2 border-blue-600 text-blue-600' : ''}
              ${index > current ? 'border-2 border-gray-300 text-gray-400' : ''}
            `}>
              {index < current ? '✓' : index + 1}
            </div>
            <span className="text-sm hidden sm:block">{step.title}</span>
          </div>
          {index < steps.length - 1 && (
            <div className={`flex-1 h-0.5 mx-3 ${index < current ? 'bg-blue-600' : 'bg-gray-200'}`} />
          )}
        </React.Fragment>
      ))}
    </div>
  );
}

Как избежать потери данных при обновлении страницы?

Самый надёжный способ — комбинировать локальное и серверное хранение. В localStorage храним текущий шаг и введённые данные. При каждом переходе отправляем частичные данные на backend (incremental approach). Даже если пользователь случайно закроет вкладку, черновик восстановится. Индикатор шагов (progress bar) визуально показывает прогресс и снижает тревожность.

Процесс работы и сроки

  1. Анализ требований — выявляем количество шагов, обязательные поля, сценарии восстановления.
  2. Проектирование UX — рисуем прототипы wizard в Figma, утверждаем с заказчиком.
  3. Реализация frontend — вёрстка компонентов, интеграция с React Hook Form, настройка Zod.
  4. Backend API — роуты для каждого шага, обработка черновиков, финальная агрегация.
  5. Тестирование — проверка всех переходов, валидации, сценариев потери данных.
  6. Деплой и мониторинг — выкатка на production, настройка логирования ошибок.

Что входит в разработку

  • Исходный код на TypeScript/React с комментариями
  • Документация API (Swagger/OpenAPI)
  • Инструкция по деплою
  • Тестовая среда
  • Поддержка в течение 30 дней после сдачи

Сроки

Multi-step wizard с React Hook Form, localStorage сохранение прогресса, поэтапный backend API, прогресс-бар: 3–5 дней на базовый функционал. Если нужна серверная синхронизация черновиков и адаптация под специфические бизнес-правила — 7–10 дней. Наша команда реализовала 15+ проектов с мультишаговой регистрацией для B2B SaaS.

Свяжитесь с нами, чтобы оценить ваш проект. Мы гарантируем, что данные не потеряются даже при неожиданном закрытии вкладки, а конверсия регистрации вырастет минимум на 20%. Закажите разработку мультишаговой регистрации и получите консультацию по интеграции с вашей CRM.

Аутентификация и авторизация: OAuth, JWT, сессии, RBAC, 2FA

На одном проекте токен JWT с ролью admin: false мог быть изменён клиентом на admin: true — сервер принимал его без верификации подписи. Это не гипотетическая атака: несколько файлов в npm-экосистеме имели уязвимость jwt библиотеки, которая игнорировала алгоритм none. Последствия — полный доступ к административным функциям для любого зарегистрированного пользователя.

JWT: что реально нужно знать

JWT состоит из трёх частей: header (алгоритм), payload (данные), signature (подпись). Подпись верифицирует, что payload не изменён. Без проверки подписи — это просто base64-encoded JSON, который любой может подделать.

Ошибки, которые видим в коде регулярно:

Хранение в localStorage. localStorage доступен любому JS на странице — XSS атака читает токен и отправляет на сервер злоумышленника. Access token в памяти (переменная модуля), refresh token в httpOnly cookie — правильная схема.

Долгоживущие access-токены. Access token на 7 дней без возможности отзыва. Утёк — 7 дней доступа. Стандарт: 15 минут для access token, 30 дней для refresh token с ротацией. При каждом использовании refresh token выдаётся новый, старый инвалидируется — если старый кто-то использует повторно, это детектируется как Token Reuse Attack, вся семья токенов отзывается.

Хранение секретных данных в payload. JWT payload не зашифрован, только подписан — его видно в base64. Пароли, платёжные данные, личная информация — не в JWT.

Алгоритм RS256 (асимметричный) предпочтительнее HS256 (симметричный) в микросервисной архитектуре: сервисы могут верифицировать токен публичным ключом, не имея доступа к секрету для его создания.

OAuth 2.0 и OpenID Connect

OAuth 2.0 — протокол делегированной авторизации, не аутентификации. «Войти через Google» — это OpenID Connect поверх OAuth 2.0, который добавляет id_token с данными пользователя.

Authorization Code Flow с PKCE — единственный правильный flow для браузерных SPA и мобильных приложений. Implicit Flow устарел и небезопасен. PKCE (Proof Key for Code Exchange) защищает от перехвата authorization code.

Реализация OAuth сервера: не пишем с нуля. Keycloak (open source, self-hosted), Auth0, Okta — готовые решения. Laravel Passport или Laravel Sanctum для серверных приложений. NextAuth.js для Next.js — поддерживает 50+ провайдеров из коробки.

Для B2B продуктов с корпоративными клиентами — SAML 2.0 SSO. Корпоративные IT-отделы часто требуют его вместо OAuth. @boxyhq/saml-jackson — node.js библиотека для SAML → OAuth2 адаптера.

Сессии vs токены

Сессии хранят состояние на сервере (Redis, database) — сервер может мгновенно отозвать сессию. При масштабировании на несколько инстансов нужен общий store (Redis Cluster). Cookie с session ID — httpOnly, Secure, SameSite=Strict.

Stateless JWT не требуют server-side storage, масштабируются горизонтально. Но отзыв токена до истечения срока — только через blacklist (Redis), что частично убирает преимущество stateless.

Для большинства веб-приложений сессии проще и безопаснее. JWT имеет смысл для API, потребляемых из мобильного приложения, и для микросервисной архитектуры.

RBAC и политики доступа

Role-Based Access Control — у пользователя есть роли, у ролей — права. Простая реализация: user → roles → permissions. Но как только появляется ресурсная авторизация («пользователь может редактировать только свои посты»), RBAC усложняется.

Spatie Laravel Permission — стандарт для Laravel: полиморфные роли и права, кэширование, super-admin через gate. Интеграция с Eloquent: $user->can('edit posts'), $user->hasRole('editor').

ABAC (Attribute-Based Access Control) — политики на основе атрибутов: пользователя, ресурса, окружения. Нужен когда правила доступа сложные: «менеджер может просматривать заказы своего региона, если заказ создан более 24 часов назад». Casbin — популярная cross-language библиотека для ABAC.

ReBAC (Relationship-Based Access Control) — Google Zanzibar model. Доступ определяется графом отношений: «пользователь X является участником команды Y, которая имеет доступ к проекту Z». OpenFGA — open source реализация от Okta.

Двухфакторная аутентификация

TOTP (Time-based One-Time Password, Google Authenticator, Authy) — стандарт. Библиотеки: otplib (Node.js), pragmarx/google2fa (Laravel). QR-код при подключении — base32-encoded secret, которого достаточно для воспроизведения кода при компрометации. Хранить secret в зашифрованном виде.

SMS-верификация — слабее TOTP из-за SIM-swapping атак и ненадёжности доставки SMS. Но пользователи активируют её охотнее. Email OTP — компромисс между безопасностью и UX.

WebAuthn (Passkeys) — биометрия или аппаратный ключ вместо пароля. Хранится private key на устройстве, публичный — на сервере. Нет пароля — нет его утечки. iOS 16+, Android 9+, все современные браузеры поддерживают. @simplewebauthn/server + @simplewebauthn/browser — хорошая библиотека для Node.js реализации.

Backup-коды при подключении 2FA: 10 одноразовых кодов для восстановления доступа если телефон потерян. Хранить хешированными (bcrypt), показывать только один раз при генерации.

Типичные уязвимости

Broken Object Level Authorization (BOLA/IDOR): /api/orders/12345 возвращает заказ без проверки, принадлежит ли он текущему пользователю. Самая распространённая уязвимость API по OWASP. Каждый запрос к ресурсу — проверка через $user->can('view', $order).

Mass Assignment: User::create($request->all()) — пользователь передаёт is_admin: true в теле запроса. Laravel решает через $fillable / $guarded, но часто забывают.

Небезопасный CORS: Access-Control-Allow-Origin: * на API с авторизацией по cookie — credentials не передаются с wildcard origin, но если кто-то сделал Allow-Credentials: true + Allow-Origin: * — это дыра.

Процесс работы

Архитектура авторизации проектируется до начала разработки, не добавляется потом. Выбор между сессиями и JWT, структура ролей и прав, flow для OAuth-провайдеров, план для 2FA. Penetration testing обязателен для продуктов с финансовыми данными или персональными данными пользователей.

Сроки

Базовая аутентификация (email/password + OAuth + JWT/сессии): 1–3 недели. RBAC с детальными политиками доступа: 2–4 недели. 2FA (TOTP + SMS): 1–2 недели. WebAuthn/Passkeys: 2–3 недели. Полная система аутентификации для SaaS с multi-tenancy: 4–8 недель.