Защищенные маршруты

Защищённые маршруты (protected routes) позволяют ограничивать доступ к определённым страницам приложения, обеспечивая контроль над тем, какие пользователи могут просматривать конкретный контент. В Page.js это реализуется через комбинацию маршрутизации и проверки состояния пользователя, чаще всего авторизации.

Page.js работает на основе клиентской маршрутизации, где каждая функция-обработчик маршрута получает объект контекста, содержащий URL, параметры и состояние. Использование защищённых маршрутов предполагает проверку состояния пользователя перед выполнением перехода.


Настройка базового маршрута

import page from 'page';

// Определение публичного маршрута
page('/', () => {
    console.log('Главная страница');
});

// Определение маршрута входа
page('/login', () => {
    console.log('Страница входа');
});

В этом примере маршруты доступны всем пользователям. Для защищённых маршрутов необходимо добавить проверку авторизации.


Реализация проверки авторизации

Для контроля доступа создаётся middleware — промежуточная функция, которая выполняется перед основным обработчиком маршрута.

function requireAuth(ctx, next) {
    const isAuthenticated = Boolean(localStorage.getItem('token'));
    
    if (isAuthenticated) {
        next(); // пользователь авторизован, продолжаем
    } else {
        page('/login'); // перенаправляем на страницу входа
    }
}

Здесь requireAuth проверяет наличие токена в localStorage. Если токен отсутствует, пользователь автоматически перенаправляется на страницу логина. Если токен присутствует — вызывается next(), позволяя обработчику маршрута выполняться дальше.


Применение middleware к защищённым маршрутам

Middleware можно подключать как к отдельным маршрутам, так и к группе маршрутов:

// Защищённый маршрут
page('/dashboard', requireAuth, () => {
    console.log('Панель пользователя');
});

// Ещё один защищённый маршрут
page('/profile', requireAuth, () => {
    console.log('Профиль пользователя');
});

Page.js обрабатывает маршруты последовательно. Сначала вызывается middleware requireAuth, и только при успешной проверке выполняется функция рендеринга страницы.


Группировка защищённых маршрутов

Если несколько маршрутов требуют одинаковой проверки, удобнее создавать группы маршрутов:

function protectedRoute(route, handler) {
    page(route, requireAuth, handler);
}

protectedRoute('/settings', () => {
    console.log('Настройки пользователя');
});

protectedRoute('/account', () => {
    console.log('Управление аккаунтом');
});

Такой подход упрощает поддержку и масштабирование приложения, предотвращая дублирование проверок авторизации.


Асинхронная проверка доступа

В реальных приложениях авторизация часто требует обращения к серверу, чтобы подтвердить токен или права доступа. Middleware легко адаптируется под асинхронные операции:

async function requireAuthAsync(ctx, next) {
    try {
        const token = localStorage.getItem('token');
        const response = await fetch('/api/validate-token', {
            headers: { 'Authorization': `Bearer ${token}` }
        });

        if (response.ok) {
            next();
        } else {
            page('/login');
        }
    } catch (error) {
        page('/login');
    }
}

page('/dashboard', requireAuthAsync, () => {
    console.log('Панель пользователя с асинхронной проверкой');
});

Асинхронная проверка позволяет удостовериться, что токен действителен и пользователь имеет соответствующие права перед рендерингом контента.


Управление состоянием пользователя

Для гибкой работы с защищёнными маршрутами полезно хранить состояние авторизации в централизованном хранилище (например, Redux или простой объект):

const auth = {
    isAuthenticated: false,
    login(token) {
        localStorage.setItem('token', token);
        this.isAuthenticated = true;
    },
    logout() {
        localStorage.removeItem('token');
        this.isAuthenticated = false;
    }
};

function requireAuthWithState(ctx, next) {
    if (auth.isAuthenticated) {
        next();
    } else {
        page('/login');
    }
}

page('/dashboard', requireAuthWithState, () => {
    console.log('Панель пользователя с контролем через состояние');
});

Такое решение позволяет динамически менять доступность маршрутов без постоянной проверки localStorage.


Перенаправление после успешного входа

Часто требуется вернуть пользователя на защищённый маршрут после авторизации. Для этого сохраняется целевой URL:

let redirectTo = '/';

function requireAuth(ctx, next) {
    if (auth.isAuthenticated) {
        next();
    } else {
        redirectTo = ctx.path;
        page('/login');
    }
}

// После успешного входа
function loginSuccess() {
    auth.login('example-token');
    page(redirectTo);
}

Такой подход улучшает пользовательский опыт и обеспечивает плавную навигацию.


Комбинирование с параметрами маршрутов

Page.js поддерживает динамические сегменты URL, что полезно для защищённых страниц профиля или деталей ресурса:

page('/profile/:userId', requireAuth, (ctx) => {
    console.log(`Профиль пользователя с ID: ${ctx.params.userId}`);
});

Middleware requireAuth срабатывает перед обработчиком, обеспечивая безопасность даже при динамических URL.


Резюме подходов

  • Middleware — основной механизм контроля доступа.
  • Асинхронные проверки позволяют интегрировать серверную авторизацию.
  • Состояние пользователя удобно хранить централизованно для масштабируемых приложений.
  • Перенаправления после логина повышают удобство навигации.
  • Динамические маршруты безопасны при использовании middleware.

Эти инструменты в комбинации позволяют создавать надёжные и масштабируемые защищённые маршруты в Page.js, обеспечивая плавную и безопасную клиентскую навигацию.