Mithril — это легковесный JavaScript-фреймворк для создания одностраничных приложений (SPA), в котором маршрутизация и управление состоянием играют ключевую роль. Защита маршрутов и авторизация пользователей строится на логике проверки состояния приложения и динамического управления доступом к компонентам и страницам.
В Mithril маршруты определяются с помощью
m.route(), где каждому пути соответствует компонент.
Простейшая маршрутизация выглядит так:
m.route(document.body, "/", {
"/": Home,
"/dashboard": Dashboard,
"/login": Login
});
Чтобы защитить маршрут, необходимо реализовать проверку состояния пользователя до того, как будет отображён компонент. Обычно это состояние авторизации хранится в глобальном объекте или сервисе:
const Auth = {
user: null,
login(userData) {
this.user = userData;
},
logout() {
this.user = null;
},
isAuthenticated() {
return this.user !== null;
}
};
Mithril позволяет использовать функцию onmatch при
определении маршрута. Она выполняется до того, как компонент будет
загружен, что делает её идеальной для проверки авторизации:
m.route(document.body, "/", {
"/": Home,
"/dashboard": {
onmatch() {
if (!Auth.isAuthenticated()) {
return Login;
}
return Dashboard;
}
},
"/login": Login
});
В этом примере, если пользователь не авторизован, попытка перейти на
/dashboard приведёт к загрузке компонента
Login. Этот подход позволяет динамически контролировать
доступ к страницам.
В реальных приложениях часто необходимо проверять авторизацию на
сервере, используя API. Mithril поддерживает асинхронные операции в
onmatch, возвращая промис:
m.route(document.body, "/", {
"/profile": {
onmatch() {
return m.request({ method: "GET", url: "/api/check-auth" })
.then(response => {
if (response.authenticated) {
return Profile;
} else {
return Login;
}
});
}
}
});
Такая конструкция позволяет выполнять асинхронную проверку прав доступа без нарушения логики маршрутизации.
Помимо защиты маршрутов, авторизацию часто реализуют внутри компонентов, управляя видимостью элементов интерфейса:
const Navbar = {
view() {
return m("nav", [
m("a[href='/']", "Главная"),
Auth.isAuthenticated() ? m("a[href='/dashboard']", "Панель") : null,
Auth.isAuthenticated() ? m("button", { onclick: () => Auth.logout() }, "Выйти") :
m("a[href='/login']", "Войти")
]);
}
};
Таким образом, элементы интерфейса подстраиваются под состояние пользователя, создавая ощущение защищённого пространства.
Для централизованного контроля доступа удобно использовать обёртку компонентов. Создаётся функция, которая принимает компонент и возвращает новый с проверкой авторизации:
function Protected(component) {
return {
oninit(vnode) {
if (!Auth.isAuthenticated()) {
m.route.set("/login");
}
},
view(vnode) {
return Auth.isAuthenticated() ? m(component, vnode.attrs) : null;
}
};
}
Использование:
m.route(document.body, "/", {
"/dashboard": Protected(Dashboard),
"/login": Login
});
Такой подход обеспечивает единый механизм защиты всех приватных компонентов, упрощает поддержку и масштабирование приложения.
В сложных приложениях требуется различать уровни доступа. Можно
расширить объект Auth и проверку маршрутов:
const Auth = {
user: null,
login(userData) { this.user = userData; },
logout() { this.user = null; },
hasRole(role) { return this.user && this.user.roles.includes(role); }
};
m.route(document.body, "/", {
"/admin": {
onmatch() {
if (!Auth.isAuthenticated() || !Auth.hasRole("admin")) {
return Login;
}
return AdminPanel;
}
}
});
Так реализуется контроль доступа по ролям, позволяющий разделять права пользователей и администраторов.
Для устойчивости авторизации важно сохранять состояние между
перезагрузками страницы. Чаще всего используется
localStorage или sessionStorage:
const Auth = {
user: JSON.parse(localStorage.getItem("user")),
login(userData) {
this.user = userData;
localStorage.setItem("user", JSON.stringify(userData));
},
logout() {
this.user = null;
localStorage.removeItem("user");
},
isAuthenticated() {
return this.user !== null;
}
};
Это позволяет поддерживать сессию даже при обновлении браузера и интегрировать защиту маршрутов с хранением состояния.
onmatch для защиты маршрутов, чтобы
минимизировать рендеринг нежелательных компонентов.Protected) для
унификации логики защиты.localStorage или sessionStorage.За счёт этих подходов Mithril позволяет создавать безопасные SPA с гибким контролем доступа, при этом сохраняя лёгкость и быстроту работы фреймворка.