Рассмотрим основные способы настройки аутентификации: от входа и регистрации до работы с социальными сетями и кастомными моделями пользователей.
248 открытий191 показов
Во время аутентификации происходит проверка пользователя: учетные данные сопоставляются с теми, что хранятся в системе. Если указана неверная комбинация логина и пароля, доступ к функционалу веб-приложения будет ограничен.
Такой механизм реализован и на сайте Tproger: читатели не могут создавать, комментировать и лайкать посты, пока не пройдут аутентификацию.
Базовая аутентификация в Django
Фреймворк Django выбирают для аутентификации из-за его встроенной, безопасной и гибкой системы управления пользователями. Это готовые инструменты для регистрации, авторизации и настройки прав доступа, включая защиту от основных типов атак, безопасное хранение паролей и управление сессиями. При этом в Django система аутентификации легко настраивается под нужды проекта, подробно документирована и регулярно обновляется.
Установим фреймворк командой pip:
pip install django
Создадим новый проект:
django-admin startproject myproject cd myproject
Создадим новое приложение для работы с аутентификацией:
python manage.py startapp myapp
Django уже содержит встроенную систему аутентификации. Она находится в приложении django.contrib.auth, которое по умолчанию включено в INSTALLED_APPS в файле settings.py.
Добавим приложение в список INSTALLED_APPS:
INSTALLED_APPS = [ ... 'myapp', ]
Добавление и настройка страниц для входа, регистрации и выхода
Используем встроенные формы Django, чтобы настроить аутентификацию. Сначала создадим поля для входа и регистрации в файле forms.py приложения myapp:
from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User class LoginForm(forms.Form): username = forms.CharField(label='Username') password = forms.CharField(label='Password', widget=forms.PasswordInput) class RegisterForm(UserCreationForm): email = forms.EmailField(required=True) class Meta: model = User fields = ['username', 'email', 'password1', 'password2']
Код выше создает две формы: LoginForm
для входа и RegisterForm
для регистрации нового пользователя.
Форма LoginForm содержит два поля: username и password. Поле password отображается как поле ввода пароля с помощью виджета PasswordInput.
Форма RegisterForm наследуется от встроенной формы UserCreationForm и добавляет дополнительное поле email. В классе Meta указываем модель User и поля, которые нужно включить в форму.
Топ пакетов для улучшения работы с Pythontproger.ru
Создадим представления для обработки запросов входа, регистрации и выхода. В файле views.py приложения myapp добавим код:
from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login, logout from .forms import LoginForm, RegisterForm def login_view(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] password = form.cleaned_data['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('home') else: form = LoginForm() return render(request, 'login.html', {'form': form}) def register_view(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): form.save() return redirect('login') else: form = RegisterForm() return render(request, 'register.html', {'form': form}) def logout_view(request): logout(request) return redirect('login')
Код выше создает три функции представления: login_view, register_view и logout_view.
Функция login_view обрабатывает запрос входа пользователя. Для POST-запроса создается экземпляр формы LoginForm с переданными данными. Если форма валидна, извлекаются имя, пароль и выполняется аутентификация пользователя с помощью функции authenticate()
. Если пользователь успешно аутентифицирован, выполняется вход login()
, и пользователь перенаправляется на главную. Для GET-запроса, создается пустая форма LoginForm, которая передается в шаблон login.html.
Функция register_view обрабатывает запрос регистрации.
- Если это POST-запрос, создается экземпляр формы RegisterForm с переданными данными.
- Если форма валидна, новый пользователь сохраняется в базе данных с помощью метода save(), и перенаправляется на страницу входа.
- Если это GET-запрос, создается пустая форма RegisterForm, которая передается в шаблон register.html.
Функция logout_view
обрабатывает запрос завершения сессии. Она вызывает функцию logout()
для выхода пользователя, и перенаправляет его на страницу входа.
Создадим шаблоны login.html, register.html и добавим ссылку на выход в шаблоне base.html:
<!-- login.html --> <h2>Войти</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Войти</button> </form>
<!-- register.html --> <h2>Зарегистрироваться</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Зарегистрироваться</button> </form>
<!-- base.html --> <!DOCTYPE html> <html> <head> <title>{% block title %}My Site{% endblock %}</title> </head> <body> <header> {% if user.is_authenticated %} <p>Добро пожаловать, {{ user.username }}! <a href="{% url 'logout' %}">Выйти</a></p> {% else %} <p><a href="{% url 'login' %}">Войти</a> | <a href="{% url 'register' %}">Зарегистрироваться</a></p> {% endif %} </header> {% block content %} {% endblock %} </body> </html>
В шаблоне base.html добавляем условие {% if user.is_authenticated %} — оно проверит, авторизован ли пользователь. Если авторизован, отобразится приветствие и ссылка на выход. Если не авторизован, то появятся ссылки на страницы входа и регистрации.
Обновим файл urls.py приложения myapp, чтобы добавить маршруты для новых представлений:
from django.urls import path from . import views urlpatterns = [ path('login/', views.login_view, name='login'), path('register/', views.register_view, name='register'), path('logout/', views.logout_view, name='logout'), ]
Запустим сервер, чтобы протестировать вход и регистрацию:
python manage.py runserver
Страницы размещаются по адресу http://localhost:8000/login/ и http://localhost:8000/register/ соответственно.
В Django также есть встроенные классы представлений для аутентификации, такие как LoginView и LogoutView. Чтобы использовать их, обновим файл urls.py приложения myapp:
from django.urls import path from django.contrib.auth import views as auth_views from . import views urlpatterns = [ path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'), path('register/', views.register_view, name='register'), path('logout/', auth_views.LogoutView.as_view(next_page='login'), name='logout'), ]
Заменили функцию представления login_view на класс представления LoginView и указали шаблон login.html. Аналогично, заменили функцию представления logout_view на класс представления LogoutView и указали страницу, на которую будет перенаправлен пользователь после выхода (next_page=’login’).
Управление доступом с помощью авторизации
Один из распространенных способов ограничения доступа — использование декоратора @login_required. Его можно применять к функциям представления, чтобы разрешить доступ только авторизованным пользователям.
Для использования декоратора @login_required обновим файл settings.py и укажем URL-адрес для перенаправления неавторизованных пользователей:
LOGIN_URL = '/login/'
Теперь в файле views.py приложения myapp добавим следующий код:
from django.contrib.auth.decorators import login_required @login_required def home_view(request): return render(request, 'home.html')
Код создает функцию представления home_view
, которая отображает главную страницу сайта. Применяем декоратор @login_required к этой функции, чтобы разрешить доступ только авторизованным пользователям.
Создадим шаблон home.html в директории templates приложения myapp:
<!-- home.html --> {% extends 'base.html' %} {% block content %} <h2>Добро пожаловать на домашнюю страницу!</h2> <p>Это защищенная страница. Доступ к нему могут получить только авторизованные пользователи.</p>{% endblock %}
Добавим путь для главной страницы в файле urls.py приложения myapp:
from django.urls import path from . import views urlpatterns = [ path('', views.home_view, name='home'), # ... ]
Если неавторизованный пользователь попытается получить доступ к главной странице, он будет перенаправлен на страницу входа.
В Django есть система разрешений (permissions) для расширенного управления доступом. С их помощью можно определять, какие действия могут выполнять пользователи или группы пользователей.
Создадим группу и назначим ей разрешения. В файле admin.py приложения myapp добавим следующий код:
from django.contrib import admin from django.contrib.auth.models import Group, Permission admin.site.register(Group) admin.site.register(Permission)
Создадим функцию представления, которая будет доступна только пользователям с определенным разрешением. В файле views.py приложения myapp добавим код:
from django.contrib.auth.decorators import permission_required @permission_required('myapp.view_special_page') def special_page_view(request): return render(request, 'special_page.html')
Создаем функцию представления special_page_view, которая отображает специальную страницу. Применяем декоратор @permission_required к этой функции и указываем необходимое разрешение myapp.view_special_page. Только пользователи или группы с этим разрешением смогут получить доступ к данной странице.
Создадим шаблон special_page.html в директории templates приложения myapp:
<!-- special_page.html --> {% extends 'base.html' %} {% block content %} <h2>Добро пожаловать на специальную страницу!</h2> <p>Эта страница доступна только пользователям с особыми разрешениями.</p> {% endblock %}
Добавим маршрут для специальной страницы в файле urls.py приложения myapp:
from django.urls import path from . import views urlpatterns = [ # ... path('special/', views.special_page_view, name='special_page'), ]
Теперь только пользователи или группы с разрешением myapp.view_special_page смогут получить доступ к специальной странице.
Расширение модели пользователя
Можно создать собственную модель пользователя, наследуя от AbstractUser или AbstractBaseUser.
Давайте ассмотрим создание кастомной модели пользователя с помощью AbstractUser. В файле models.py приложения myapp добавим код:
from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): phone_number = models.CharField(max_length=20, blank=True) address = models.TextField(blank=True) def __str__(self): return self.username
Создаем класс CustomUser, который наследуется от AbstractUser. Добавляем дополнительные поля phone_number и address к модели пользователя.
Обновим файл settings.py и укажем кастомную модель:
AUTH_USER_MODEL = 'myapp.CustomUser'
С этого момента система аутентификации будет использовать кастомную модель пользователя вместо встроенной модели User.
Создадим миграции и применим их для обновления базы данных:
python manage.py makemigrations python manage.py migrate
Для работы с кастомной моделью нужно обновить формы. В файле forms.py приложения myapp изменим поля регистрации:
from django import forms from django.contrib.auth.forms import UserCreationForm from .models import CustomUser class CustomUserCreationForm(UserCreationForm): phone_number = forms.CharField(max_length=20, required=False) address = forms.CharField(widget=forms.Textarea, required=False) class Meta: model = CustomUser fields = ['username', 'email', 'phone_number', 'address', 'password1', 'password2']
Создаем класс CustomUserCreationForm, который наследуется от UserCreationForm. Добавляем поля phone_number и address к форме и указываем кастомную модель CustomUser в классе Meta.
Чтобы система аутентификации приняла изменения, обновим функцию представления register_view в файле views.py:
from .forms import CustomUserCreationForm def register_view(request): if request.method == 'POST': form = CustomUserCreationForm(request.POST) if form.is_valid(): form.save() return redirect('login') else: form = CustomUserCreationForm() return render(request, 'register.html', {'form': form})
Меняем форму UserCreationForm на кастомную форму CustomUserCreationForm. Теперь Django работает, используя собственную модель пользователя с дополнительными полями во всем проекте.
Социальная аутентификация
Для реализации входа через сторонние сервисы есть библиотека django-allauth. Она предоставляет готовые решения для интеграции с провайдерами социальной аутентификации.
Установим библиотеку django-allauth:
pip install django-allauth
Добавим django-allauth в список установленных приложений в файле settings.py:
INSTALLED_APPS = [ # ... 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google', # ... ] SITE_ID = 1
Добавляем приложения django.contrib.sites, allauth и провайдеры социальной аутентификации, которые хотим использовать. В нашем случае это интеграция Google.
Сотрудник Минобороны РФ получил 1.5 года за пиратскую Windows 10 на рабочем ноутбукеtproger.ru
Также устанавливаем значение SITE_ID = 1, чтобы указать идентификатор сайта.
Добавим URL-адреса для django-allauth в файле urls.py проекта:
from django.urls import path, include urlpatterns = [ # ... path('accounts/', include('allauth.urls')), # ... ]
Включаем URL-адреса django-allauth с префиксом accounts/.
Выполним миграции для создания таблиц в базе данных:
python manage.py migrate
После этого можно настраивать провайдеров социальной аутентификации через административный интерфейс Django.
Добавим кнопки для социальной аутентификации на страницу входа. В шаблоне login.html добавим следующий код:
<!-- login.html --> {% extends 'base.html' %} {% block content %} <h2>Войти</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Войти</button> </form> <h3>Или войти через:</h3> <a href="{% url 'socialaccount_signup' 'google' %}">Google</a> {% endblock %}
Добавляем ссылки на страницы регистрации через социальные аккаунты, используя URL-адреса socialaccount_signup с указанием провайдера. Теперь пользователи могут войти на сайт, используя свою учетную запись Google.
Безопасность аутентификации
Рекомендации по повышению безопасности аутентификации:
- Настройте SSL/TLS-сертификат для сайта для безопасного соединения между клиентом и сервером. Используйте протокол HTTPS для всех страниц, где есть аутентификации и передача конфиденциальных данных.
- Система на Django работает со встроенной защитой от межсайтовой подделки запросов (CSRF). Убедитесь, что в шаблонах форм используется тег {% csrf_token %}.
- Экранируйте пользовательский ввод перед его выводом на страницах сайта, чтобы защититься от межсайтового скриптинга (XSS). Django автоматически экранирует переменные в шаблонах, но будьте осторожны при явном выводе HTML.
- Для защиты от атак методом перебора (брутфорса) ограничьте количество неудачных попыток входа для каждого пользователя или IP-адреса. Используйте библиотеки django-axes или django-ratelimit, чтобы реализовать ограничения числа попыток входа.
- Никогда не храните пароли в открытом виде — вместо этого используйте хеш-функции. В Django есть встроенные функции для хеширования паролей: django.contrib.auth.hashers.make_password() и django.contrib.auth.hashers.check_password().
- Возможно, стоит реализовать двухфакторную аутентификацию, чтобы повысить безопасность учетных записей. Используйте библиотеки django-two-factor-auth или django-otp для добавления 2FA.