Пользователи: аутентификация и пароли
Django приносит готовую систему пользователей: модель User, вход, выход, регистрацию и проверку прав. Не пишите аутентификацию с нуля — это опасно.
Суть: приложение django.contrib.auth даёт модель User, хеширование паролей, функции login/logout/authenticate, декоратор login_required и систему прав. Пароли никогда не хранятся в открытом виде.
Готовая модель User
Аутентификация — критичная по безопасности область, где самодельные решения почти всегда содержат дыры. Django предоставляет проверенную систему. Модель User из django.contrib.auth хранит логин, email, пароль (в виде хеша!), флаги is_active, is_staff, is_superuser и даты. Доступ к текущему пользователю — через request.user.
Вход, выход, проверка
Три функции — основа аутентификации. authenticate проверяет логин и пароль, login создаёт сессию, logout её завершает:
from django.contrib.auth import authenticate, login, logout
def login_view(request):
if request.method == "POST":
user = authenticate(
request,
username=request.POST["username"],
password=request.POST["password"],
)
if user is not None:
login(request, user)
return redirect("home")
return render(request, "login.html")
Защита страниц
Чтобы закрыть страницу от анонимов, для функций используют декоратор @login_required, для CBV — миксин LoginRequiredMixin:
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
return render(request, "dashboard.html")
Неавторизованного пользователя Django перенаправит на страницу входа. В шаблонах проверяют {% if user.is_authenticated %}.
Как это работает под капотом: пароли
Самое важное: Django никогда не хранит пароли в открытом виде. При регистрации пароль прогоняется через медленную криптографическую хеш-функцию (по умолчанию PBKDF2) с солью. В базе лежит только хеш. При входе введённый пароль хешируется так же и сравнивается с сохранённым. Даже при утечке базы исходные пароли восстановить крайне сложно. Принцип «хешируем при регистрации, сравниваем хеши при входе» — языко-независимый. Вот его упрощённая модель:
# Попробуй сам ▶ — хеширование и проверка пароля (упрощённо)
import hashlib, os
def hash_password(password, salt=None):
salt = salt or os.urandom(8).hex()
# PBKDF2: тысячи итераций делают перебор дорогим
digest = hashlib.pbkdf2_hmac(
"sha256", password.encode(), salt.encode(), 100_000
).hex()
return f"pbkdf2_sha256$100000${salt}${digest}"
def check_password(password, stored):
_, _, salt, _ = stored.split("$")
return hash_password(password, salt) == stored
# регистрация: храним ТОЛЬКО хеш
stored = hash_password("super-secret")
print("В базе лежит:", stored[:40], "...")
# вход: сравниваем хеши, а не пароли
print("Верный пароль: ", check_password("super-secret", stored))
print("Неверный пароль: ", check_password("wrong", stored))
Django делает это надёжнее (несколько алгоритмов, автоматическое усиление при росте мощности железа), но идея ровно такая: в базе — хеш с солью, а при входе сравниваются хеши.
Сессии
После login Django создаёт сессию: в базе хранится её состояние, а браузеру выдаётся кука с идентификатором. На каждом следующем запросе SessionMiddleware и AuthenticationMiddleware по этой куке восстанавливают request.user. Так пользователь остаётся «залогиненным» между запросами.
Частые ошибки
- Писать свою аутентификацию и хранить пароли как есть. Это грубейшая уязвимость. Используйте
django.contrib.auth. - Устанавливать пароль через присваивание поля. Нужен
user.set_password(...), иначе пароль не захешируется. - Забыть @login_required на приватных страницах. Их увидят анонимы.
- Путать authenticate и login. Первый проверяет, второй создаёт сессию — нужны оба.
Best practices
- Никогда не реализуйте хранение паролей сами — доверьте Django.
- Устанавливайте пароли через
set_password, проверяйте черезcheck_password. - Защищайте приватные страницы декоратором/миксином, не полагайтесь на «скрытые» URL.
- Для расширения модели пользователя используйте кастомную
AbstractUserс самого начала проекта.
Итоги
Django даёт готовую и безопасную систему пользователей: модель User, функции authenticate/login/logout, защиту страниц через login_required. Пароли хранятся только как хеши с солью, сессии держатся на куках. Никогда не пишите аутентификацию с нуля. Дальше — встроенная защита Django от веб-атак.