Page.js — это клиентский маршрутизатор для одностраничных приложений на JavaScript, который обеспечивает управление навигацией без перезагрузки страницы. Одной из ключевых задач при создании SPA является контроль доступа к определённым маршрутам в зависимости от состояния пользователя, например, авторизован он или нет, или есть ли у него определённые роли.
В Page.js проверка прав доступа реализуется через middleware-функции, которые вызываются перед переходом на маршрут. Middleware позволяет перехватывать навигацию и выполнять логику проверки.
Middleware в Page.js — это функция с сигнатурой
(ctx, next), где:
ctx — объект контекста маршрута, содержащий информацию
о пути, параметрах, query-параметрах и пользовательском состоянии.next — функция, которая продолжает выполнение
следующего middleware или маршрута.Пример базового middleware для проверки авторизации:
function requireAuth(ctx, next) {
const user = ctx.state.user; // состояние пользователя
if (!user || !user.isLoggedIn) {
page('/login'); // перенаправление на страницу входа
} else {
next(); // доступ разрешён, продолжаем навигацию
}
}
Применение middleware к маршруту:
page('/dashboard', requireAuth, () => {
renderDashboard();
});
В этом примере, если пользователь не авторизован, он будет
перенаправлен на /login. Если авторизован, выполняется
функция renderDashboard().
Для более сложных приложений часто требуется проверять роли
пользователя. Допустим, есть роли admin,
editor и viewer. Middleware для проверки роли
может выглядеть так:
function requireRole(role) {
return function(ctx, next) {
const user = ctx.state.user;
if (!user || !user.roles.includes(role)) {
page('/not-authorized'); // доступ запрещён
} else {
next();
}
};
}
Использование:
page('/admin', requireAuth, requireRole('admin'), () => {
renderAdminPanel();
});
Такой подход позволяет чётко разделять маршруты по уровням доступа и легко расширять права для новых ролей.
В Page.js можно регистрировать middleware для всех маршрутов, что удобно для проверки авторизации на уровне всего приложения. Пример:
page('*', (ctx, next) => {
ctx.state.user = getCurrentUser(); // получение состояния пользователя
next();
});
Здесь getCurrentUser() может получать данные из
localStorage, cookie или API. Этот middleware обеспечит наличие
актуального состояния пользователя в каждом маршруте.
После этого можно комбинировать глобальные и локальные middleware:
page('*', (ctx, next) => {
ctx.state.user = getCurrentUser();
next();
});
page('/profile', requireAuth, () => {
renderProfile();
});
page('/admin', requireAuth, requireRole('admin'), () => {
renderAdminPanel();
});
Иногда проверка прав доступа требует обращения к серверу, например, для получения актуальных данных о сессии. В Page.js middleware поддерживает асинхронные операции через промисы:
function asyncRequireAuth(ctx, next) {
return fetch('/api/session')
.then(response => response.json())
.then(data => {
if (!data.isLoggedIn) {
page('/login');
} else {
ctx.state.user = data.user;
next();
}
})
.catch(() => page('/login'));
}
Использование асинхронного middleware гарантирует, что переход на маршрут произойдёт только после завершения проверки состояния пользователя.
Можно комбинировать права доступа с логикой перенаправления для разных типов пользователей:
function redirectByRole(ctx, next) {
const user = ctx.state.user;
if (!user) {
page('/login');
} else if (user.roles.includes('admin')) {
page('/admin');
} else {
page('/dashboard');
}
}
Это позволяет динамически направлять пользователей на соответствующие страницы после входа или при попытке доступа к корневому маршруту.
ctx.state:
хранение данных пользователя и состояния доступа позволяет легко
обмениваться информацией между middleware.// Глобальное состояние пользователя
page('*', async (ctx, next) => {
ctx.state.user = await fetchCurrentUser();
next();
});
// Маршрут с авторизацией и проверкой роли
page('/settings', requireAuth, requireRole('editor'), () => {
renderSettings();
});
// Маршрут доступен всем
page('/about', () => {
renderAbout();
});
Эта структура позволяет масштабировать SPA, добавлять новые маршруты и права без нарушения существующей логики доступа.