В этом руководстве мы рассмотрим, как добавить социальную аутентификацию с помощью GitHub и Google в приложение на Flask.
От редакции Pythonist: реализацию социальной аутентификации в Django мы рассматривали в статье «Аутентификация в Django-REST с помощью Auth.js».
Социальная аутентификация — это процесс аутентификации пользователя через сторонний сервис, а не через собственный. Например, кнопка «Войти с помощью Google», которую вы видите на многих сайтах, является лучшим примером социальной аутентификации. Google проверяет подлинность пользователя и предоставляет приложению токен для управления пользовательской сессией.
Использование социальной аутентификации имеет свои преимущества. Вам не нужно будет настраивать аутентификацию для веб-приложения, поскольку этим занимается сторонний провайдер OAuth. Кроме того, поскольку такие провайдеры, как Google, Facebook и GitHub, проводят тщательные проверки для предотвращения несанкционированного доступа к своим сервисам, использование социальной аутентификации вместо создания собственного механизма может повысить безопасность вашего приложения.
Наряду с Flask мы будем использовать Flask-Dance для включения социальной аутентификации, Flask-Login для регистрации пользователей и управления сессиями, а также Flask-SQLAlchemy для взаимодействия с базой данных для хранения пользовательских данных.
Почему стоит использовать социальную аутентификацию, а не создавать свою собственную?
Социальная аутентификация чаще всего реализуется с помощью 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.
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 Client ID и Client Secret, которые вы создали ранее, в новом файле .env:
GITHUB_ID=<YOUR_ID_HERE> GITHUB_SECRET=<YOUR_SECRET_HERE> OAUTHLIB_INSECURE_TRANSPORT=1
Примечания:
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)
Примечания:
В результате будут созданы две таблицы, 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, чтобы добавить таблицу 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 с моделью OAuth
db.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
Теперь, когда вы знаете шаги по подключению нового провайдера OAuth и настройке Flask-Login, вы должны суметь настроить нового провайдера.
Например, вот шаги для Google:
@app.route("/google")
) в main.py@oauth_authorized.connect_via(google_blueprint)
) в app/oauth.pyПопробуйте сделать это самостоятельно.
В этом руководстве мы подробно рассказали о том, как добавить социальный аутентификатор в приложение на Flask с помощью Flask-Dance. Настроив GitHub и Google, вы должны получить представление о том, как подключать новых провайдеров социальной аутентификации:
Ищете дополнительные задачи?
user
, а новый аккаунт в социальной сети был связан с существующим пользователем).Код можно взять из репозитория flask-social-auth на GitHub.
Перевод статьи «Adding Social Authentication to Flask».
При анализе данных часто требуется быстро найти абсолютное значение набора чисел. Для выполнения этой задачи…
Pydantic - это мощная библиотека проверки данных и управления настройками для Python, созданная для повышения…
Python предлагает набор библиотек, удовлетворяющих различные потребности в визуализации, будь то академические исследования, бизнес-аналитика или…
В Python для представления данных в двоичной форме можно использовать байты. Из этой статьи вы…
В этой статье рассказывается о том, что такое Werkzeug и как Flask использует его для…
При работе с датами часто возникает необходимость прибавлять к дате или вычитать из нее различные…