
В этом руководстве мы рассмотрим, как добавить социальную аутентификацию с помощью GitHub и Google в приложение на Flask.
От редакции Pythonist: реализацию социальной аутентификации в Django мы рассматривали в статье «Аутентификация в Django-REST с помощью Auth.js».
Социальная аутентификация — это процесс аутентификации пользователя через сторонний сервис, а не через собственный. Например, кнопка «Войти с помощью Google», которую вы видите на многих сайтах, является лучшим примером социальной аутентификации. Google проверяет подлинность пользователя и предоставляет приложению токен для управления пользовательской сессией.
Друзья, подписывайтесь на наш телеграм канал Pythonist. Там еще больше туториалов, задач и книг по Python.
Использование социальной аутентификации имеет свои преимущества. Вам не нужно будет настраивать аутентификацию для веб-приложения, поскольку этим занимается сторонний провайдер OAuth. Кроме того, поскольку такие провайдеры, как Google, Facebook и GitHub, проводят тщательные проверки для предотвращения несанкционированного доступа к своим сервисам, использование социальной аутентификации вместо создания собственного механизма может повысить безопасность вашего приложения.
Наряду с Flask мы будем использовать Flask-Dance для включения социальной аутентификации, Flask-Login для регистрации пользователей и управления сессиями, а также Flask-SQLAlchemy для взаимодействия с базой данных для хранения пользовательских данных.
Содержание
- Зачем использовать социальную аутентификацию?
- OAuth
- Flask-Dance
- Социальная аутентификация через GitHub
- Управление пользователями
- Социальная аутентификация через Google
- Заключение
Зачем использовать социальную аутентификацию?
Почему стоит использовать социальную аутентификацию, а не создавать свою собственную?
Плюсы
- Не нужно создавать собственный рабочий процесс аутентификации.
- Повышенная безопасность. Сторонние провайдеры аутентификации, такие как Google, Facebook и т. д., уделяют большое внимание безопасности. Использование таких сервисов может повысить безопасность вашего приложения.
- Можно автоматически получать имя пользователя, электронную почту и другие данные от провайдера аутентификации. Это улучшает процесс регистрации, поскольку не нужно просить пользователя вводить все это вручную.
Минусы
- Ваше приложение теперь зависит от другого приложения, которое вы не контролируете. Если стороннее приложение выйдет из строя, пользователи не смогут зарегистрироваться или войти в систему.
- Люди склонны игнорировать разрешения, запрашиваемые провайдером аутентификации. Некоторые приложения могут получить доступ к данным, которые им не требуются.
- Пользователи, не имеющие учетной записи хотя бы у одного из предложенных вами провайдеров, не смогут получить доступ к вашему приложению. Лучше всего реализовать как социальную аутентификацию, так и аутентификацию через логин и пароль, чтобы предоставить пользователю право выбора.
OAuth
Социальная аутентификация чаще всего реализуется с помощью OAuth — открытого стандартного протокола авторизации, в котором сторонний провайдер проверяет личность пользователя.
Наиболее распространенным потоком (или грантом) является код авторизации:
- Пользователь пытается войти в ваше приложение, используя свою учетную запись от стороннего провайдера авторизации.
- Пользователь перенаправляется к провайдеру аутентификации для проверки.
- После проверки они снова попадают в ваше приложение с кодом авторизации.
- Вы делаете запрос с кодом авторизации к провайдеру аутентификации для получения маркера доступа.
- После того как провайдер проверит код авторизации, он отправит обратно маркер доступа.
- После этого пользователь входит в систему и получает доступ к защищенным ресурсам.
- Токен доступа можно использовать для получения данных от провайдера.
Давайте рассмотрим быстрый пример этого потока на примере GitHub:
"""
Импортировать необходимые модули.
- `os` для чтения переменной env
- `requests` для запросов GET/POST
- `parse_qs` для парсинга ответа
"""
import os
import requests
from urllib.parse import parse_qs
"""
Определить переменные окружения GITHUB_ID и GITHUB_SECRET,
а также конечные точки.
"""
CLIENT_ID = os.getenv("GITHUB_ID")
CLIENT_SECRET = os.getenv("GITHUB_SECRET")
AUTHORIZATION_ENDPOINT = f"https://github.com/login/oauth/authorize?response_type=code&client_id={os.getenv('GITHUB_ID')}"
TOKEN_ENDPOINT = "https://github.com/login/oauth/access_token"
USER_ENDPOINT = "https://api.github.com/user"
"""
1. Войти через браузер, используя 'Authorization URL', выведенный в терминале.
(Если вы уже залогинены в GitHub, нужно или вылогиниться, или тестировать в браузере в режиме инкогнито).
2. Сразу после входа страница будет перенаправлена. Скопируйте код из URL перенаправления.
3. Вставьте код в терминал.
"""
print(f"Authorization URL: {AUTHORIZATION_ENDPOINT}")
code = input("Enter the code: ")
"""
Используя код авторизации, мы можем запросить токен доступа.
"""
# Получив код, мы отсылаем его эндпоинту токена авторизации
# (с id и secret). Ответ содержит
# access_token, который мы парсим при помощи parse_qs
res = requests.post(
TOKEN_ENDPOINT,
data=dict(
client_id=os.getenv("GITHUB_ID"),
client_secret=os.getenv("GITHUB_SECRET"),
code=code,
),
)
res = parse_qs(res.content.decode("utf-8"))
token = res["access_token"][0]
"""
Наконец, мы можем использовать токен доступа для получения информации о пользователе.
"""
user_data = requests.get(USER_ENDPOINT, headers=dict(Authorization=f"token {token}"))
username = user_data.json()["login"]
print(f"You are {username} on GitHub")
Чтобы протестировать, сохраните этот код в файл под названием oauth.py. Не забудьте просмотреть комментарии.
Далее вам нужно создать OAuth-приложение и получить OAuth-ключи от GitHub. Войдите в свой аккаунт на GitHub, а затем перейдите на https://github.com/settings/applications/new, чтобы создать новое OAuth-приложение:
Application name: Testing Flask-Dance Homepage URL: http://127.0.0.1:5000 Callback URL: http://127.0.0.1:5000/login/github/authorized

Нажмите «Register application». Вы будете перенаправлены в ваше приложение. Обратите внимание на Client ID и Client Secret:

Если Client Secret не сгенерировался, нажмите «Generate a new client secret».
Установите сгенерированные Client ID и Client Secret в качестве переменных окружения:
$ export GITHUB_ID=<your-github-id> $ export GITHUB_SECRET=<your-github-secret> # for windows machine, use `set` instead of `export`
Установите библиотеку Requests, а затем запустите скрипт:
$ pip install requests $ python oauth.py
Вы должны увидеть следующее:
Authorization URL: https://github.com/login/oauth/authorize?response_type=code&client_id=cde067521efaefe0c927 Enter the code:
Перейдите по этому URL-адресу. Авторизуйте приложение. Затем возьмите код из URL-адреса перенаправления. Например:
http://127.0.0.1:5000/login/github/authorized?code=5e54f2d755e450a64af3
Добавьте код обратно в окно терминала:
Authorization URL: https://github.com/login/oauth/authorize?response_type=code&client_id=cde067521efaefe0c927 Enter the code: 5e54f2d755e450a64af3
Вы должны увидеть имя пользователя GitHub, выведенное следующим образом:
You are mjhea0 on GitHub
А теперь давайте рассмотрим, как добавить социальную аутентификацию в приложение на Flask.
Flask-Dance
OAuthLib — это популярная, хорошо поддерживаемая библиотека Python, которая реализует OAuth. Хотя вы можете использовать эту библиотеку отдельно, в этом руководстве мы будем использовать Flask-Dance.
Flask-Dance — это библиотека, построенная поверх OAuthLib и предназначенная специально для Flask. Она имеет простой API, позволяющий быстро добавить социальный аутентификатор в приложение на Flask. Она также является самой популярной среди библиотек OAuth, разработанных для Flask.
Создайте новое приложение Flask, активируйте виртуальное окружение и установите необходимые зависимости:
$ mkdir flask-social-auth && cd flask-social-auth $ python3.12 -m venv .venv $ source .venv/bin/activate (.venv)$ pip install Flask==3.0.2 Flask-Dance==7.0.1 python-dotenv==1.0.1
Далее создайте файл main.py:
# main.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/ping")
def ping():
return jsonify(ping="pong")
if __name__ == "__main__":
app.run(debug=True)
Запустите сервер:
(.venv)$ python main.py
Перейдите по адресу http://127.0.0.1:5000/ping. Вы должны увидеть следующее:
{
"ping": "pong"
}
Социальная аутентификация через GitHub
Сохраните GitHub Client ID и Client Secret, которые вы создали ранее, в новом файле .env:
GITHUB_ID=<YOUR_ID_HERE> GITHUB_SECRET=<YOUR_SECRET_HERE> OAUTHLIB_INSECURE_TRANSPORT=1
Примечания:
- Поскольку мы установили python-dotenv, Flask будет автоматически устанавливать переменные окружения из файла .env при запуске приложения.
- OAUTHLIB_INSECURE_TRANSPORT=1 требуется в целях тестирования, так как OAuthLib по умолчанию требует HTTPS.
Flask-Dance предоставляет Flask blueprints (шаблоны) для каждого провайдера. Давайте создадим такой blueprint для провайдера GitHub в файле app/oauth.py:
# app/oauth.py
import os
from flask_dance.contrib.github import make_github_blueprint
github_blueprint = make_github_blueprint(
client_id=os.getenv("GITHUB_ID"),
client_secret=os.getenv("GITHUB_SECRET"),
)
Импортируйте и зарегистрируйте blueprint в main.py и проложите новый маршрут:
# main.py
from flask import Flask, jsonify, redirect, url_for
from flask_dance.contrib.github import github
from app.oauth import github_blueprint
app = Flask(__name__)
app.secret_key = "supersecretkey"
app.register_blueprint(github_blueprint, url_prefix="/login")
@app.route("/ping")
def ping():
return jsonify(ping="pong")
@app.route("/github")
def login():
if not github.authorized:
return redirect(url_for("github.login"))
res = github.get("/user")
return f"You are @{res.json()['login']} on GitHub"
if __name__ == "__main__":
app.run(debug=True)
Маршрут /github перенаправляет на GitHub для проверки, если пользователь еще не вошел в систему. После входа отображается имя пользователя.
Запустите приложение, выполнив команду python main.py. Перейдите на http://127.0.0.1:5000/github и протестируйте приложение. После проверки на GitHub вы будете перенаправлены обратно. Вы должны увидеть что-то типа этого:
You are @mjhea0 on GitHub
Управление пользователями
Теперь давайте подключим Flask-Login для управления сессиями пользователей и Flask-SQLAlchemy для добавления поддержки SQLAlchemy, чтобы хранить данные о пользователях в базе данных.
Установите зависимости:
(.venv)$ pip install Flask-Login==0.6.3 Flask-SQLAlchemy==3.1.1 SQLAlchemy-Utils==0.41.1
Модели
Создайте модели для хранения информации о пользователях и OAuth в новом файле app/models.py:
# app/models.py
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, LoginManager
from flask_dance.consumer.storage.sqla import OAuthConsumerMixin
db = SQLAlchemy()
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(250), unique=True)
class OAuth(OAuthConsumerMixin, db.Model):
user_id = db.Column(db.Integer, db.ForeignKey(User.id))
user = db.relationship(User)
login_manager = LoginManager()
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
Примечания:
- OAuthConsumerMixin из Flask-Dance автоматически добавит необходимые поля для хранения информации OAuth.
- LoginManager из Flask-Login будет извлекать пользователей из таблицы user.
В результате будут созданы две таблицы, user и flask_dance_oauth:
# user table name type -------- ------------ id INTEGER username VARCHAR(250) # flask_dance_oauth table name type ---------- ----------- id INTEGER provider VARCHAR(50) created_at DATETIME token TEXT user_id INTEGER
GitHub blueprint
Далее измените созданный ранее GitHub blueprint, чтобы добавить таблицу OAuth в качестве хранилища:
# app/oauth.py
import os
from flask_login import current_user
from flask_dance.contrib.github import make_github_blueprint
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage
from app.models import OAuth, db
github_blueprint = make_github_blueprint(
client_id=os.getenv("GITHUB_ID"),
client_secret=os.getenv("GITHUB_SECRET"),
storage=SQLAlchemyStorage(
OAuth,
db.session,
user=current_user,
user_required=False,
),
)
Здесь мы передали:
storageкак хранилище SQLAlchemy с модельюOAuthdb.session, который являетсяsqlalchemy.session- пользователя как
current_userиз Flask Login
Конечные точки
Давайте определим соответствующие конечные точки в main.py — login, logout и homepage:
# main.py
from flask import Flask, jsonify, redirect, render_template, url_for
from flask_dance.contrib.github import github
from flask_login import logout_user, login_required
from app.models import db, login_manager
from app.oauth import github_blueprint
app = Flask(__name__)
app.secret_key = "supersecretkey"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///./users.db"
app.register_blueprint(github_blueprint, url_prefix="/login")
db.init_app(app)
login_manager.init_app(app)
with app.app_context():
db.create_all()
@app.route("/ping")
def ping():
return jsonify(ping="pong")
@app.route("/")
def homepage():
return render_template("index.html")
@app.route("/github")
def login():
if not github.authorized:
return redirect(url_for("github.login"))
res = github.get("/user")
username = res.json()["login"]
return f"You are @{username} on GitHub"
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(url_for("homepage"))
if __name__ == "__main__":
app.run(debug=True)
Здесь мы инициализировали db и login_manager, определенные ранее в models.py.
Представление homepage отображает шаблон index.html, который мы скоро добавим. Далее представление login аутентифицирует пользователя на GitHub и возвращает имя пользователя. Маршрут logout выводит пользователя из системы.
Все маршруты уже настроены, но мы еще не вошли в систему. Для этого мы воспользуемся сигналами Flask (Signals).
Сигналы
Сигналы позволяют выполнять действия при наступлении предопределенных событий. В нашем случае мы будем регистрировать пользователя при успешной аутентификации через GitHub.
Для работы сигналов требуется Binker, поэтому установите его прямо сейчас:
(.venv)$ pip install blinker==1.7.0
Добавьте новый helper в app/oauth.py:
# app/oauth.py
import os
from flask_login import current_user, login_user
from flask_dance.consumer import oauth_authorized
from flask_dance.contrib.github import github, make_github_blueprint
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage
from sqlalchemy.orm.exc import NoResultFound
from app.models import db, OAuth, User
github_blueprint = make_github_blueprint(
client_id=os.getenv("GITHUB_ID"),
client_secret=os.getenv("GITHUB_SECRET"),
storage=SQLAlchemyStorage(
OAuth,
db.session,
user=current_user,
user_required=False,
),
)
@oauth_authorized.connect_via(github_blueprint)
def github_logged_in(blueprint, token):
info = github.get("/user")
if info.ok:
account_info = info.json()
username = account_info["login"]
query = User.query.filter_by(username=username)
try:
user = query.one()
except NoResultFound:
user = User(username=username)
db.session.add(user)
db.session.commit()
login_user(user)
Когда пользователь подключается через github_blueprint, выполняется функция github_logged_in. Она принимает два параметра: blueprint и token (от GitHub). Затем мы получаем имя пользователя от провайдера и выполняем одно из двух действий:
- Если имя пользователя уже присутствует в таблицах, мы обеспечиваем пользователю вход.
- Если нет — создаем нового пользователя, а затем обеспечиваем ему вход.
Шаблоны
Наконец, давайте добавим шаблоны:
(.venv)$ mkdir templates && cd templates (.venv)$ touch _base.html (.venv)$ touch index.html
Шаблон _base.html содержит общий макет:
<!-- templates/_base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flask Social Login</title>
</head>
<body style="padding-top: 10%;">
{% block content %} {% endblock content %}
</body>
</html>
Далее добавим кнопку «Login with GitHub» в index.html:
<!-- templates/index.html -->
{% extends '_base.html' %}
{% block content %}
<div style="text-align:center;">
{% if current_user.is_authenticated %}
<h1>You are logged in as {{current_user.username}}</h1>
<br><br>
<a href="{{url_for('logout')}}" class="btn btn-danger">Logout</a>
{% else %}
<!-- GitHub button starts here -->
<a href="{{url_for('login')}}" class="btn btn-secondary">
<i class="fa fa-github fa-fw"></i>
<span>Login with GitHub</span>
</a>
<!-- GitHub button ends here -->
{% endif %}
</div>
{% endblock content %}
После этого запустите приложение и перейдите по адресу http://127.0.0.1:5000. Протестируйте поток аутентификации.
Структура проекта:
├── .env
├── app
│ ├── __init__.py
│ ├── models.py
│ └── oauth.py
├── main.py
└── templates
├── _base.html
└── index.html
Социальная аутентификация через Google
Теперь, когда вы знаете шаги по подключению нового провайдера OAuth и настройке Flask-Login, вы должны суметь настроить нового провайдера.
Например, вот шаги для Google:
- Создать приложение OAuth в Google
- Настроить Google blueprint в файле app/oauth.py
- Настроить маршрут для перенаправления на вход в Google в файле main.py
- Создать новую конечную точку для входа в Google (
@app.route("/google")) в main.py - Создать новый сигнал Flask для входа пользователя в систему, когда он аутентифицируется через Google (
@oauth_authorized.connect_via(google_blueprint)) в app/oauth.py - Обновить шаблон templates/index.html
Попробуйте сделать это самостоятельно.
Заключение
В этом руководстве мы подробно рассказали о том, как добавить социальный аутентификатор в приложение на Flask с помощью Flask-Dance. Настроив GitHub и Google, вы должны получить представление о том, как подключать новых провайдеров социальной аутентификации:
- Получить токены для каждого провайдера, создав OAuth-приложения
- Настроить модели баз данных для хранения данных пользователей и OAuth
- Создать blueprint для каждого провайдера и добавить созданную модель OAuth в качестве хранилища
- Добавить маршрут для аутентификации у провайдера
- Добавить сигнал для входа пользователя в систему после аутентификации
Ищете дополнительные задачи?
- Разберитесь, как связать несколько логинов в социальных сетях с одним аккаунтом (чтобы при входе пользователя через аккаунт в другой социальной сети не создавалась новая строка в таблице
user, а новый аккаунт в социальной сети был связан с существующим пользователем). - Получите от социального провайдера дополнительную информацию о пользователе (например, email, язык, страну), указав области OAuth.
Код можно взять из репозитория flask-social-auth на GitHub.
Перевод статьи «Adding Social Authentication to Flask».

