Главная Веб-разработка Как настроить аутентификацию в веб-приложениях на Django – Tproger

Как настроить аутентификацию в веб-приложениях на Django – Tproger

от admin

Рассмотрим основные способы настройки аутентификации: от входа и регистрации до работы с социальными сетями и кастомными моделями пользователей.

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 к этой функции, чтобы разрешить доступ только авторизованным пользователям.

Читать также:
Что такое Bluetooth и как он работает

Создадим шаблон 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.

Похожие статьи