OAuth 2.0 — это протокол делегированной авторизации. Вместо того чтобы создавать и хранить пароль на нашем сайте, пользователь входит через стороннюю платформу (GitHub, ВКонтакте), которая подтверждает его личность и передаёт нам базовую информацию: имя, email, аватар.
Это удобно для пользователя — не нужно запоминать ещё один пароль. И снижает ответственность нашего приложения — мы не храним пароли вообще, если пользователь авторизовался только через соцсеть.
Принципиальная схема работает так:
Пользователь нажимает «Войти через GitHub»
↓
Браузер переходит на GitHub — пользователь подтверждает доступ
↓
GitHub перенаправляет обратно на наш сайт с временным кодом
↓
Наш сервер обменивает код на access token
↓
Наш сервер запрашивает данные пользователя у GitHub по токену
↓
Django создаёт или находит пользователя в БД и входит от его имени
Весь этот механизм реализует библиотека python-social-auth — нам остаётся только настроить параметры.
pip install social-auth-app-djangoДобавляем в INSTALLED_APPS и подключаем маршруты:
# filmsite/settings.py
INSTALLED_APPS = [
# ... существующие приложения ...
'social_django',
]# filmsite/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('social_django.urls', namespace='social')),
path('accounts/login/', LoginView.as_view(authentication_form=CustomAuthenticationForm), name='login'),
path('accounts/', include('django.contrib.auth.urls')),
path('accounts/register/', RegisterView.as_view(), name='register'),
path('', include('films.urls')),
]Применяем миграции — social_django создаёт свои таблицы для хранения связей между Django-пользователями и их OAuth-профилями:
python manage.py migratepython-social-auth тоже работает через механизм бэкендов аутентификации, который мы разобрали в уроке 24. Добавляем бэкенды для GitHub и ВКонтакте в settings.py:
# filmsite/settings.py
AUTHENTICATION_BACKENDS = [
'social_core.backends.github.GithubOAuth2', # GitHub
'social_core.backends.vk.VKOAuth2', # ВКонтакте
'films.backends.EmailAuthBackend', # наш бэкенд — вход по email
'django.contrib.auth.backends.ModelBackend', # стандартный — вход по username
]GitHub OAuth работает на localhost — это удобно для разработки и позволяет протестировать всё прямо сейчас.
- Открой github.com/settings/developers
- Нажми «New OAuth App»
- Заполни поля:
| Поле | Значение |
|---|---|
| Application name | filmsite-local |
| Homepage URL | http://localhost:8000 |
| Authorization callback URL | http://localhost:8000/auth/complete/github/ |
- Нажми «Register application»
- На следующей странице скопируй Client ID
- Нажми «Generate a new client secret» и скопируй секрет — он показывается один раз
# filmsite/settings.py
SOCIAL_AUTH_GITHUB_KEY = 'твой_client_id'
SOCIAL_AUTH_GITHUB_SECRET = 'твой_client_secret'Учётные данные через переменные окружения — по тому же принципу, что DB и SMTP:
import os
SOCIAL_AUTH_GITHUB_KEY = os.environ.get('GITHUB_KEY', '')
SOCIAL_AUTH_GITHUB_SECRET = os.environ.get('GITHUB_SECRET', '')# filmsite/settings.py
LOGIN_REDIRECT_URL = '/' # уже настроено в уроке 23python-social-auth использует LOGIN_REDIRECT_URL после успешной OAuth-авторизации — дополнительных настроек не нужно.
<!-- templates/registration/login.html -->
{% extends 'base.html' %}
{% block title %}Вход — Сайт фильмов{% endblock %}
{% block content %}
<h1>Вход на сайт</h1>
{% if form.errors %}
<p class="error">Неверное имя пользователя/email или пароль.</p>
{% endif %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="next" value="{{ next }}">
<button type="submit">Войти</button>
</form>
<hr>
<p>Войти через:</p>
<form action="{% url 'social:begin' 'github' %}" method="post">
{% csrf_token %}
<button type="submit">
Войти через GitHub
</button>
</form>
<form action="{% url 'social:begin' 'vk-oauth2' %}" method="post">
{% csrf_token %}
<button type="submit">
Войти через ВКонтакте
</button>
</form>
<p>Ещё нет аккаунта? <a href="{% url 'register' %}">Зарегистрироваться</a></p>
<p><a href="{% url 'password_reset' %}">Забыли пароль?</a></p>
{% endblock %}Тег {% url 'social:begin' 'github' %} строит URL вида /auth/login/github/ — это точка входа, после которой python-social-auth сам перенаправляет пользователя на GitHub.
Запусти сервер и открой http://localhost:8000/accounts/login/. Нажми «GitHub» — должен открыться экран авторизации GitHub. После подтверждения пользователь вернётся на главную страницу. В административной панели в разделе «Social Auth» → «User social auths» появится запись с привязкой.
Важное ограничение: ВКонтакте не принимает
localhostкак доверенный redirect URI — при попытке получишь ошибкуredirect_uri is incorrect. Настройку ВК выполним полностью, но проверить её можно будет только после деплоя сайта на реальный сервер с доменным именем — это разберём в модуле 9.Если хочешь протестировать OAuth ВКонтакте локально прямо сейчас — посмотри в сторону ngrok: он создаёт публичный HTTPS-туннель к localhost за несколько минут. Официальная документация: ngrok.com/docs.
- Перейди на dev.vk.com и нажми «Создать приложение»
- Укажи:
- Название:
filmsite - Платформа: Сайт
- Нажми «Подключить сайт»
- Название:
- На следующем шаге укажи URL сайта — адрес твоего домена (например,
https://filmsite.ru). На локальном адресеhttp://localhost:8000ВК вернёт ошибку. - После создания перейди в Настройки → скопируй ID приложения и Защищённый ключ
# filmsite/settings.py
SOCIAL_AUTH_VK_OAUTH2_KEY = os.environ.get('VK_KEY', '') # ID приложения
SOCIAL_AUTH_VK_OAUTH2_SECRET = os.environ.get('VK_SECRET', '') # Защищённый ключ
# Запрашиваем email при авторизации
SOCIAL_AUTH_VK_OAUTH2_SCOPE = ['email']SOCIAL_AUTH_VK_OAUTH2_SCOPE — список прав, которые мы запрашиваем у пользователя при входе. ВКонтакте по умолчанию не передаёт email — его нужно явно запросить через scope. Без этого поле email у созданного пользователя окажется пустым.
Ссылка на полную документацию по бэкенду ВКонтакте для python-social-auth: python-social-auth.readthedocs.io/en/latest/backends/vk.html
Кнопка входа через ВКонтакте уже добавлена в шаблон выше — {% url 'social:begin' 'vk-oauth2' %} готова и заработает автоматически после деплоя.
Несколько параметров, которые стоит добавить в settings.py для корректной работы:
# filmsite/settings.py
# Если пользователь с таким email уже существует — связать аккаунты
SOCIAL_AUTH_ASSOCIATE_BY_EMAIL = True
# Pipeline — последовательность шагов при OAuth-входе
# Стандартный pipeline подходит для большинства случаев
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
)SOCIAL_AUTH_ASSOCIATE_BY_EMAIL = True — важная настройка: если пользователь уже зарегистрирован через форму с тем же email, что и его GitHub/ВК аккаунт, Django свяжет эти аккаунты вместо создания дубля.
Pipeline — это цепочка функций, которые выполняются при каждом OAuth-входе. Стандартный pipeline: получить данные от провайдера → найти или создать пользователя → связать OAuth-профиль с Django-пользователем → обновить детали. При необходимости в pipeline можно вставить собственный шаг — например, автоматическое создание UserProfile при первом входе через соцсеть.
В уроке 26 мы настроили автосоздание UserProfile через RegisterView. Но при входе через OAuth RegisterView не вызывается — пользователь создаётся внутри pipeline. Добавим свой шаг:
# films/pipeline.py
from .models import UserProfile
def create_user_profile(backend, user, response, *args, **kwargs):
"""Создаёт UserProfile при первом входе через OAuth, если его нет."""
UserProfile.objects.get_or_create(user=user)Добавляем в конец pipeline:
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'films.pipeline.create_user_profile', # наш шаг — последним
)# filmsite/settings.py
INSTALLED_APPS = [
# ... существующие приложения ...
'social_django',
]
AUTHENTICATION_BACKENDS = [
'social_core.backends.github.GithubOAuth2',
'social_core.backends.vk.VKOAuth2',
'films.backends.EmailAuthBackend',
'django.contrib.auth.backends.ModelBackend',
]
# GitHub OAuth (работает на localhost)
SOCIAL_AUTH_GITHUB_KEY = os.environ.get('GITHUB_KEY', '')
SOCIAL_AUTH_GITHUB_SECRET = os.environ.get('GITHUB_SECRET', '')
# ВКонтакте OAuth (требует реальный домен)
SOCIAL_AUTH_VK_OAUTH2_KEY = os.environ.get('VK_KEY', '')
SOCIAL_AUTH_VK_OAUTH2_SECRET = os.environ.get('VK_SECRET', '')
SOCIAL_AUTH_VK_OAUTH2_SCOPE = ['email']
SOCIAL_AUTH_ASSOCIATE_BY_EMAIL = True
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'films.pipeline.create_user_profile',
)Ещё раз явно: ВК отклоняет redirect URI с localhost или 127.0.0.1. Даже указав в настройках приложения ВК адрес http://localhost:8000, при попытке авторизации получишь ошибку redirect_uri is incorrect. Это ограничение платформы, не наш код. Единственные варианты для локального тестирования — ngrok или развёрнутый сервер с доменом.
Ссылка {% url 'social:begin' 'vk-oauth2' %} будет генерироваться корректно и до деплоя — кнопка будет видна и кликабельна. Но переход по ней завершится ошибкой со стороны ВКонтакте (redirect_uri is incorrect). Это не ошибка в нашем коде — просто ограничение платформы.
Без SOCIAL_AUTH_ASSOCIATE_BY_EMAIL = True пользователь, зарегистрировавшийся через форму с email ivan@example.com, а потом вошедший через GitHub с тем же email, получит второй Django-аккаунт. Включённая настройка объединяет их. Но стоит знать: это создаёт потенциальную уязвимость — злоумышленник теоретически может захватить аккаунт, создав OAuth-профиль с чужим email. В реальных проектах вместе с этой настройкой часто включают подтверждение email при регистрации.
Ссылка {% url 'social:begin' 'github' %} не содержит client_id в явном виде — это просто URL нашего сервера, который уже знает client_id из settings.py. Так и должно быть: client_id не является секретом (он виден в redirect URL), но client_secret никогда не должен попадать во фронтенд.
- Зачем нужна библиотека
python-social-authпри реализации OAuth 2.0 в Django? - Почему авторизация ВКонтакте не работает на
localhostи как это обойти? - Что такое pipeline в
python-social-authи зачем он нужен? - Зачем нужна настройка
SOCIAL_AUTH_ASSOCIATE_BY_EMAIL = Trueи какой риск она несёт? - Зачем нужен параметр
SOCIAL_AUTH_VK_OAUTH2_SCOPE = ['email']?
Тип: расширь проект
Часть 1 (выполняется сейчас — GitHub). Создай OAuth-приложение на GitHub, добавь настройки в settings.py через переменные окружения. Добавь кнопки «GitHub» и «ВКонтакте» на страницу входа. Проверь, что авторизация через GitHub работает локально — после входа пользователь должен появиться в разделе «Social Auth» в административной панели.
Часть 2 (выполняется после деплоя — ВКонтакте). Создай приложение на dev.vk.com, укажи реальный домен сайта, сохрани ключи в переменных окружения на сервере. После деплоя в модуле 9 проверь авторизацию через ВКонтакте.
Для обеих частей: добавь файл films/pipeline.py с функцией create_user_profile и включи её в SOCIAL_AUTH_PIPELINE. Убедись, что при первом OAuth-входе для пользователя автоматически создаётся UserProfile.