Ось готовий урок, створений за твоїм майстер-промптом. Вмикаємо режим CS50! 🚀
🛡️ Урок: Захищені маршрути та авторизація
Привіт, друзі! Мене звати [Твоє Ім'я], і це... CS50 (ну, майже)!
Сьогодні ми не просто пишемо код. Сьогодні ми стаємо охоронцями власної фортеці. Готові? Поїхали!
1. 🔥 Вступ: Чому не можна просто "увійти"?
Уявіть, що ви збудували шикарний готель. У вас є номери «Стандарт» і є «Президентський люкс» із джакузі та безкоштовним мінібаром.
Питання до вас: Чи хотіли б ви, щоб будь-хто з вулиці міг просто піднятися на ліфті, зайти в «Президентський люкс» і випити весь сік, навіть не зареєструвавшись на рецепції?
Звісно, ні! Це було б катастрофою для бізнесу.
У веб-розробці це працює так само. У вашому додатку є сторінки, які доступні всім (Головна, «Про нас»), а є «Президентські люкси» — це Особистий кабінет, Налаштування, Адмін-панель.
Якщо ми не захистимо ці маршрути (routes), будь-хто, хто знає URL-адресу /admin/delete-all-users, зможе знищити ваш проєкт одним кліком.
Сьогодні ми навчимося ставити надійного швейцара перед дверима наших важливих сторінок. Цей швейцар називається Protected Route (Захищений маршрут).
2. 🧠 Теоретична база: Як працює "швейцар"
Давайте заглянемо під капот. Тут немає ніякої магії, лише проста логіка. Але спочатку — два терміни, які плутають 90% початківців.
🔑 Аутентифікація vs Авторизація
- Аутентифікація (Authentication): Відповідь на питання «Хто ти?».
- Аналогія: Ви показуєте паспорт на кордоні. Прикордонник бачить: "Ага, це Іван".
- Авторизація (Authorization): Відповідь на питання «Що тобі можна робити?».
- Аналогія: Паспорт у вас є, але чи є у вас віза або квиток у VIP-зону?
Як це працює в коді?
Уявіть маршрутизатор (Router) як коридор з дверима.
Без захисту: Людина натискає на ручку дверей /dashboard -> Двері відчиняються -> Людина бачить контент.
Із захистом (Protected Route):
Людина натискає на ручку /dashboard -> СТОП! ✋
Тут вмикається наш код-перехоплювач (часто це компонент-обгортка або Middleware). Він робить перевірку:
ЯКЩО (користувач_залогінений == TRUE) {
Пропускаємо далі (Render Component)
} ІНАКШЕ {
Відправляємо на сторінку входу (Redirect to /login)
}
Обовʼязково запам’ятати: Захищений маршрут на клієнті (фронтенді) — це лише візуальна зручність. Справжня безпека даних завжди знаходиться на сервері (бекенді). Але сьогодні ми фокусуємося на тому, як не пустити "чужинця" на сторінку інтерфейсу.
3. 🧪 Приклади (від ідеї до коду)
Давайте напишемо це. Я буду використовувати синтаксис React, оскільки це найпопулярніший приклад, але логіка ідентична для Vue, Angular чи навіть звичайного HTML/JS.
Приклад 1: "Наївний" підхід (Мінімальний)
Уявіть, що у вас є компонент Dashboard.
Що ви очікуєте побачити в коді? Напевно, просто перевірку if всередині компонента.
function Dashboard({ user }) {
// Якщо користувача немає — викидаємо його
if (!user) {
return <Navigate to="/login" />;
}
// Якщо є — показуємо секретні дані
return <h1>Привіт, {user.name}! Ось твій баланс: $1,000,000</h1>;
}
Чому це погано? Уявіть, що у вас 50 таких сторінок. Вам доведеться писати цей if п'ятдесят разів! Це порушує принцип DRY (Don't Repeat Yourself).
Приклад 2: Паттерн "Охоронець" (Типовий для реальних проєктів)
Давайте створимо окремий компонент-обгортку. Назвемо його ProtectedRoute. Це і є наш швейцар.
// Компонент-швейцар
const ProtectedRoute = ({ user, children }) => {
// 1. Перевірка: чи є користувач?
if (!user) {
// 2. Якщо ні — до побачення, йдіть логінитись
return <Navigate to="/login" replace />;
}
// 3. Якщо так — проходьте (рендеримо дочірні компоненти)
return children;
};
А тепер ми використовуємо його в нашому додатку:
<Routes>
<Route path="/" element={<Home />} />
{/* Загортаємо секретну сторінку в охоронця */}
<Route
path="/dashboard"
element={
<ProtectedRoute user={currentUser}>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
Бачите красу? Компонент Dashboard тепер нічого не знає про перевірки. Він просто робить свою роботу. А ProtectedRoute займається безпекою.
Приклад 3: "Тільки для адмінів" (Трохи складніше)
А що, якщо користувач залогінений, але він звичайний студент, а хоче зайти в "Учительську"?
const AdminRoute = ({ user, children }) => {
// Спочатку перевіряємо, чи він взагалі увійшов
if (!user) {
return <Navigate to="/login" />;
}
// А тепер перевіряємо РОЛЬ (Авторизація)
if (user.role !== 'admin') {
return <h1>Вибачте, доступ заборонено! Тільки для босів. 🚫</h1>;
}
return children;
};
4. 🛠 Практична частина
Час забруднити руки кодом! Відкрийте свій редактор (або уявіть його) і спробуйте вирішити ці задачі.
🔹 Завдання 1: Повторення
Напишіть функцію ProtectedRoute на папері або в редакторі, не підглядаючи в приклад вище. Логіка: "Немає юзера? Редірект. Є? Рендер children".
🔹 Завдання 2: "А куди я йшов?" (UX кейс)
Коли користувача викидає на логін, це дратує, якщо після входу його кидає на "Головну", а не туди, куди він хотів.
Задача: Дослідіть (або придумайте), як передати поточний шлях в сторінку /login, щоб після успішного входу повернути людину назад.
🔹 Завдання 3: Стан завантаження
У реальному житті перевірка користувача займає час (запит на сервер).
Задача: Додайте в ProtectedRoute умову: if (isLoading) return <Spinner />. Що буде, якщо цієї умови не буде? (Спойлер: користувача може викинути на логін ще до того, як сервер скаже "Привіт").
🔹 Завдання 4: Міні-кейс "Guest Route"
Ми захистили /dashboard від незареєстрованих.
Але тепер захистіть сторінку /login від... зареєстрованих!
Задача: Якщо я вже увійшов у систему і йду на /login, мене має перекинути одразу в /dashboard. Навіщо мені логінитись двічі?
5. 💡 Мислення як у розробника
Ви вже знаєте синтаксис. Тепер давайте навчимося думати як сеньйор-розробник.
❌ Помилка новачка: "Ілюзія безпеки"
Новачок думає: "Я приховав кнопку 'Видалити' на фронтенді і поставив ProtectedRoute. Все, хакери не пройдуть!"
Як думає профі:
Профі знає, що Frontend-код виконується в браузері користувача. Я можу відкрити консоль розробника, змінити змінну isAdmin = true і ваш ProtectedRoute пропустить мене.
Тому:
1. Frontend захист — це для зручності (User Experience), щоб юзер не тицяв туди, куди не можна.
2. Backend захист — це для безпеки. Кожен API запит на сервер має перевіряти токен ще раз.
💡 Порада з практики
Не зберігайте статус авторизації просто як true/false в локальному стейті компонента. Використовуйте глобальний стейт (Context, Redux, Zustand). Чому? Бо коли ви оновите сторінку (F5), локальний стейт зникне, і користувача викине, навіть якщо він залогінений.
6. 🧩 Підсумок
Отже, що ми сьогодні зробили?
- Ми зрозуміли, що не всі двері мають бути відчинені.
- Ми створили компонент-швейцара (
ProtectedRoute), який перевіряє перепустки. - Ми розібрали різницю між "Хто ти?" (Аутентифікація) і "Чи можна тобі?" (Авторизація).
Тепер ви вмієте будувати безпечні маршрути у ваших додатках. Ваш додаток більше не прохідний двір!
🕵️ Тизер наступного уроку: Добре, швейцар працює. Але звідки він знає, що перепустка справжня? Наступного разу ми поговоримо про JWT токени, LocalStorage та Cookies. Ми дізнаємось, як зберігати секрети так, щоб їх не вкрали.
А поки що — це був CS50. Щасти вам!