Автентифікація vs Авторизація — Основи¶
Для кого: Студенти, які вперше вивчають безпеку вебзастосунків у Django. Проєкт:
crispy_notes_chat_app(lesson_Django_authentication_and_security)
1. Що таке Автентифікація і Авторизація?¶
Це два абсолютно різних поняття, які часто плутають. Запам'ятай:
| Поняття | Запитання | Приклад |
|---|---|---|
| Автентифікація (Authentication) | Хто ти? | Перевірка логіну і пароля |
| Авторизація (Authorization) | Що тобі можна? | Чи маєш право видалити цю нотатку? |
Аналогія з реального життя: - Ти приходиш на роботу і показуєш посвідчення охоронцю → це автентифікація (хто ти) - Охоронець перевіряє, чи маєш ти доступ до серверної кімнати → це авторизація (що тобі дозволено)
У реальних системах ці процеси суворо розділені. Користувач може успішно автентифікуватись (увійти в систему), але не мати авторизації на перегляд чужих нотаток.
2. Архітектура автентифікації Django¶
Django має вбудовану систему автентифікації. Ось ключові компоненти:
User — основна модель¶
from django.contrib.auth.models import User
# Кожен зареєстрований користувач — це об'єкт User:
user = User.objects.get(username='alice')
print(user.username) # 'alice'
print(user.is_authenticated) # True
request.user — хто зараз відвідує сторінку¶
# У кожному view є request.user:
def my_view(request):
if request.user.is_authenticated:
# Користувач увійшов у систему
print(f"Привіт, {request.user.username}!")
else:
# Анонімний відвідувач
print("Будь ласка, увійдіть")
Django автоматично додає request.user до кожного запиту через Middleware.
authenticate() і login() / logout()¶
from django.contrib.auth import authenticate, login, logout
# Перевіряє логін і пароль:
user = authenticate(request, username='alice', password='secret')
# Якщо пароль вірний → повертає об'єкт User
# Якщо невірний → повертає None
if user is not None:
login(request, user) # Зберігає user ID у сесії (cookie)
# Тепер request.user == user
# Вихід:
logout(request) # Видаляє сесію. request.user стає AnonymousUser
3. Lifecycle HTTP-запиту та роль Middleware¶
Проблема: HTTP — це протокол без стану (stateless). Кожен запит незалежний, сервер не "пам'ятає" попередні.
Рішення: Cookies та сесії. Коли Аліса входить, сервер: 1. Зберігає її ID у базі даних (запис сесії) 2. Відправляє браузеру cookie з session ID (унікальний рядок) 3. При наступному запиті браузер автоматично надсилає цей cookie 4. Сервер знаходить сесію та знає, що це Аліса
Як Middleware обробляє кожен запит¶
Middleware — це як фільтри, крізь які проходить кожен запит перед тим, як потрапити до твого view:
Браузер надсилає запит
↓
SecurityMiddleware ← перевіряє HTTPS, заголовки безпеки
↓
SessionMiddleware ← зчитує cookie, завантажує сесію з БД
↓
CsrfViewMiddleware ← перевіряє CSRF-токен для POST-запитів
↓
AuthenticationMiddleware ← знаходить ID юзера в сесії, ставить request.user
↓
Твій View ← тут вже є request.user з правильним юзером
Діаграма lifecycle¶
graph TD
A[Браузер: запит з cookie] --> B[SessionMiddleware]
B -->|Завантажує дані сесії| C[AuthenticationMiddleware]
C -->|Додає request.user| D{Перевірка доступу у View}
D -- Не авторизований --> E[302 Редирект на логін]
D -- Авторизований --> F[Виконати логіку View]
F --> G[HTTP Відповідь]
4. Практичний приклад: @login_required¶
Декоратор @login_required — найпростіший спосіб захистити view:
from django.contrib.auth.decorators import login_required
@login_required # Якщо не авторизований → redirect на /accounts/login/
def note_list(request):
# Тут гарантовано request.user.is_authenticated == True
notes = Note.objects.filter(user=request.user) # ← ОБОВ'ЯЗКОВО фільтруй!
return render(request, 'note_list.html', {'notes': notes})
Важливо: @login_required перевіряє лише факт входу в систему, але НЕ перевіряє чи нотатки належать саме цьому юзеру. Тому треба завжди фільтрувати queryset по user=request.user.
5. Повна діаграма автентифікації та авторизації¶
graph TD
A[Браузер] --> B[SessionMiddleware]
B --> C[AuthenticationMiddleware]
C -->|Додає request.user| D{Чи авторизований?}
D -- Ні --> E[Редирект на логін]
D -- Так --> F{Чи має право? <br> note.user == request.user}
F -- Ні --> G[403 Forbidden]
F -- Так --> H[Виконати View]
Де це в нашому проєкті?¶
| Де | Що відбувається |
|---|---|
settings.py → MIDDLEWARE |
Порядок Middleware: SessionMiddleware → AuthenticationMiddleware |
notes_app/views.py |
@login_required на кожному захищеному view |
selectors.py |
Note.objects.filter(user=user) — фільтрація по власнику |
settings.py |
LOGIN_URL, LOGIN_REDIRECT_URL — куди перенаправляти |