Сообщить об ошибке.

Аутентификация с модулем requests в Python

Пользовательская аутентификация на сайтах

Библиотека requests позволяет указать собственный механизм аутентификации, а так же поддерживает без дополнительной настройки механизм базовой аутентификации.

Реализации аутентификации являются подклассами AuthBase и легко поддаются определению. Библиотека requests предоставляет две общие реализации схемы аутентификации в подмодуле requests.auth: HTTPBasicAuth и HTTPDigestAuth.

Пользовательский механизм аутентификации.

Любой вызываемый объект, который передается в качестве аргумента auth методу запроса, имеет возможность изменить запрос перед его отправкой.

Представим, что у есть веб-сервис, который будет отвечать только в том случае, если заголовок X-Pizza имеет значение пользователя. Это маловероятно, ну просто представим такую схему.

from requests.auth import AuthBase

class PizzaAuth(AuthBase):
    """Присоединяет HTTP аутентификацию к объекту запроса."""
    def __init__(self, username):
        # здесь настроем любые данные, связанные с аутентификацией 
        self.username = username

    def __call__(self, req):
        # изменяем и возвращаем запрос
        req.headers['X-Pizza'] = self.username
        return req

Затем можно сделать запрос, используя созданный класс PizzaAuth():

>>> requests.get('http://pizzabin.org/admin', auth=PizzaAuth('superken'))
# <Response [200]>

Пример базовой аутентификации.

Библиотека requests позволяет легко использовать многие формы аутентификации, включая очень распространенную базовую аутентификацию.

# псевдокод (необходимо определить используемые переменные)

>>> from requests.auth import HTTPBasicAuth
# указываем параметры аутентификации
>>> auth = HTTPBasicAuth('fake@example.com', 'password')

>>> resp = requests.post(url=url, data=body, auth=auth)
>>> resp.status_code
# 201
>>> content = resp.json()
>>> print(content['body'])

Расширение Requests-OAuthlib.

Расширение requests-oauthlib позволяет автоматически выполнять OAuth1 и OAuth2 аутентификацию из библиотеки requests без танцев с бубном.

Расширение будет полезно для большого числа веб-сайтов, которые используют OAuth1/2 для обеспечения быстрой аутентификации. Оно также предоставляет множество настроек, которые обрабатывают способы, которыми конкретные поставщики OAuth отличаются от стандартных спецификаций.

Для начала использования requests-oauthlib, его необходимо установить.

$ pip install requests_oauthlib

Расширение использует библиотеки Python requests и |OAuthlib|, чтобы предоставить простой в использовании интерфейс для создания клиентов OAuth1 и OAuth2.

В приведенном ниже примере показано веб-приложение, использующее веб-фреймворк Flask, которое подключается к API Github OAuth2. Этот пример должен быть легко перенесен на любой веб-фреймворк.

Хотя последовательность операций у большинства провайдеров остается неизменной, особенность Github заключается в том, что параметр redirect_uri является необязательным. Это означает, что может потребоваться явная передача redirect_uri объекту OAuth2Session (например, при создании настраиваемого OAuthProvider с помощью |flask-oauthlib|).

from requests_oauthlib import OAuth2Session
from flask import Flask, request, redirect, session, url_for
from flask.json import jsonify
import os

app = Flask(__name__)

# Эта информация получена при регистрации нового приложения
# GitHub OAuth здесь: https://github.com/settings/applications/new
client_id = "<your client key>"
client_secret = "<your client secret>"
authorization_base_url = 'https://github.com/login/oauth/authorize'
token_url = 'https://github.com/login/oauth/access_token'

@app.route("/")
def demo():
    """1: Авторизация пользователя.
    Перенаправление пользователя/владельца ресурса к поставщику 
    OAuth (например, Github) использование URL-адреса с несколькими
    ключевыми параметрами OAuth.
    """
    github = OAuth2Session(client_id)
    authorization_url, state = github.authorization_url(authorization_base_url)

    # Состояние используется для предотвращения CSRF, оставим на потом.
    session['oauth_state'] = state
    return redirect(authorization_url)


# 2: Авторизация пользователя, это происходит на провайдере.

@app.route("/callback", methods=["GET"])
def callback():
    """ 3: Получение токена доступа.
    Пользователь был перенаправлен обратно от поставщика на 
    зарегистрированный URL обратного вызова. С этим перенаправлением 
    приходит код авторизации, включенный в URL-адрес перенаправления. 
    Используем это, чтобы получить маркер доступа.
    """

    github = OAuth2Session(client_id, state=session['oauth_state'])
    token = github.fetch_token(token_url, client_secret=client_secret,
                               authorization_response=request.url)

    # На этом этапе уже можно получить защищенные ресурсы, сохраним 
    # токен и покажем, как это делается из сохраненного токена в /profile.
    session['oauth_token'] = token

    return redirect(url_for('.profile'))


@app.route("/profile", methods=["GET"])
def profile():
    """Извлечение защищенного ресурса с помощью токена OAuth 2.
    """
    github = OAuth2Session(client_id, token=session['oauth_token'])
    return jsonify(github.get('https://api.github.com/user').json())


if __name__ == "__main__":
    # Это позволяет нам использовать вызов по HTTP 
    os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = "1"

    app.secret_key = os.urandom(24)
    app.run(debug=True)

Обратите внимание, что Oauth2 работает через уровень SSL. Если сервер не настроен для поддержки HTTPS, то метод fetch_token вызовет ошибку oauthlib.oauth2.rfc6749.errors.InsecureTransportError. Большинство людей не устанавливают SSL на своих серверах во время тестирования, и это нормально. Можно отключить эту проверку двумя способами:

  1. Установив переменную окружения.

    export OAUTHLIB_INSECURE_TRANSPORT=1
    
  2. Эквивалентно пункту (1), можно установить это через Python (если есть проблемы с настройкой переменных окружения).

    # Где-то в webapp_example.py, например, 
    # перед запуском приложения.
    import os
    os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'