Authomatic: python библиотека для аутентификации и авторизации

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

    Магия авторизации происходит строго по протоколу OAuth 1.0а и OAuth 2.0 и значительно упрощает жизнь и владельцу веб-приложения и самому пользователю.

    Остается сущая мелочь, реализовать нужный протокол применительно к конкретному веб-приложению. Регистрация и вход в веб сервис TheOnlyPage с использованием учетных записей Facebook, Google, LinkedIn и Microsoft Live работают благодаря python библиотеке Authomatic.

    Согласно документации Authomatic обладает следующими замечательными особенностями:

    • Слабая связанность.
    • Компактный, но мощный интерфейс
    • Единственная, причем необязательная зависимость: библиотека python-openid
    • CSRF защита
    • Благодаря адаптерам нет привязки к конкретному фреймворку. Сразу из коробки поддерживается Django, Flask и Webapp2.
    • Возможность включать новые появляющиеся протоколы авторизации и аутентификации
    • Запросы к программному интерфейсу (API) провайдера — проще некуда.
    • Поддержка асинхронных запросов
    • В качестве бонуса javascript-библиотека
    • Сразу из коробки поддержка:
      • OAuth 1.0a провайдеров: Bitbucket, Flickr, Meetup, Plurk, Twitter, Tumblr, UbuntuOne,Vimeo, Xero, Xing and Yahoo
      • OAuth 2.0 провайдеров: Behance, Bitly, Cosm, DeviantART, Facebook, Foursquare,GitHub, Google, LinkedIn, PayPal, Reddit, Viadeo, VK, WindowsLive, Yammer и Yandex.
      • python-openid и OpenID основанного на Google App Engine

    Вдобавок ко всему отмечается, что библиотека находится на очень раннем этапе создания, и практически не протестирована.

    Несмотря на такое самокритичное заявление, если обратиться к демонстрационной страничке, можно убедиться что библиотека обеспечивает беспроблемную работу со всевозможными провайдерами OAuth 1.0a и OAuth 2.0.

    Качественная документация даёт достаточно информации для использования библиотеки совместно с фреймворками: Django, Flask, Pyramid и Webapp2.

    Проиллюстрируем работу с Authomatic на примере из реальной жизни. Для того чтобы зарегистрироваться / войти в веб-сервис TheOnlyPage посредством учетной записи Facebook, Google, LinkedIn и Microsoft Live достаточно кликнуть по соответствующей кнопке, на странице входа в сервис:

    image


    Процесс авторизации реализован при помощи библиотеки Authomatic. При этом TheOnlyPage работает на фреймворке Flask. Для того чтобы задействовать библиотеку Authomatic в связке с фреймворком Flask, при условии что библиотека уже присутствует в рабочем пространстве, нужно:

    1. Зарегистрировать свое приложение в каждом из OAuth-провайдеров.
    2. Добавить параметры OAuth-провайдеров в конфигурационный файл.
    3. Инициировать базовый объект authomatic параметрами, хранящимися в конфигурационном файле.
    4. Создать представление, которое выполнит запрос к провайдеру и получит от него результат.

    Проделаем эти 4 нехитрых шага:

    Регистрация приложения


    У каждого провайдера свои особенности регистрации. Адреса регистрации приложения

    для Facebook: developers.facebook.com/apps

    для Google: console.developers.google.com/project

    для LinkedIn: www.linkedin.com/secure/developer

    для Microsoft Live: account.live.com/developers/applications/create

    Некоторые параметры, которые потребуется указать, у разных провайдеров могут отличаться, но среди остальных параметров обязательно присутствуют:

    1. адреса нашего сервиса, с которых разрешен редирект с запросом к провайдеру
    2. адрес, по которому провайдер возвращает пользователя к нашему сервису после предоставления доступа
    3. адрес, по которому провайдер возвращает пользователя к нашему сервису при отказе в предоставлении доступа

    В случае использования библиотеки Authomatic в 1-м и 2-м случае удобно указать один и тот же адрес, так для соответствующих провайдеров будем использовать адреса:

    www.theonlypage.com/login/facebook

    www.theonlypage.com/login/google

    www.theonlypage.com/login/linkedin

    www.theonlypage.com/login/microsoft

    Также на страничке регистрации приложения у провайдера, нам надо получить код пользователя и секретный ключ, в терминах различных провайдеров они соответственно называются:
    код пользователя секретный ключ
    Facebook App ID App Secret
    Google Client ID Client secret
    LinkedIn API Key Secret Key
    Microsoft Live Client ID Client secret

    Кроме того, в разделе регистрации приложения у провайдера, мы должны выяснить под каким названием фигурируют нужные нам данные. Например, адрес электронной почты пользователя обозначается:

    для Facebook: email

    для Google: email

    для LinkedIn: r_emailaddress

    для Microsoft Live: wl.emails

    После того как приложение зарегистрировано во всех провайдерах, адреса редиректа указаны, код пользователя и секретный ключ получены, есть ясность как именуются данные применительно к каждому провайдеру, можно переходить к настройке конфигурационного файла.

    Определение конфигурации OAuth провайдеров


    В стандартный конфигурационный файл flask-приложения нужно добавить словарь содержащий параметры всех провайдеров:

    OAUTH_CONFIG = {
      'facebook': {          
        'class_': oauth2.Facebook,
        'consumer_key': 123456789012345',
        'consumer_secret': ' edcba987654321012345679abcdedcab',
        'scope': ['email',],
      },
        'google': {
        'class_': oauth2.Google,
        'consumer_key': '123456789098.apps.googleusercontent.com',
        'consumer_secret': ' ABcDEFgiJKLmNOPQRStUVWxyz ',
        'scope': ['email',],
      },
      'linkedin': {
        'class_': oauth2.LinkedIn,
        'consumer_key': ' ABC123df45GIJ6h ',
        'consumer_secret': ‘zyx987vutSRQponM ',
        'scope': ['r_emailaddress',],
      },
        'microsoft': {        
        'class_': oauth2.WindowsLive,
        'consumer_key': '0000000012345A67',
        'consumer_secret': ' ABcDe123fgHIJK45LmnO6789PQrS0tUVXyz ',
        'scope': ['wl.emails',],
      },
    }
    

    Как видим каждому провайдеру ставится в соответствие словарь со следующими атрибутами:

    class_ — входящий в состав библиотеки Authomatic класс, соответствующий очередному провайдеру;

    consumer_key — код пользователя у очередного провайдера;

    consumer_secret — секретный ключ очередного провайдера;

    scope — список данных, которые предполагается запрашивать у очередного провайдера.

    Предварительные установки сделаны.

    Инициация базового объекта authomatic


    Происходит очень просто, с указаним конфигурационных данных и секретной строки:

    from authomatic import Authomatic
    from config import OAUTH_CONFIG 
    authomatic = Authomatic(OAUTH_CONFIG, ‘very secret string', report_errors=False)
    

    Создание представления


    Осталось создать представление, которое:
    • соответствует интернет адресу с которого осуществляется редирект запроса данных к провайдеру и получение данных от провайдера;
    • осуществляет получение электронного адреса пользователя от oauth-провайдера;
    • и, если этот пользователь зарегистрирован в системе – открывает ему доступ.

    import re
    from authomatic.adapters import WerkzeugAdapter
    
    from flask import redirect, make_response
    from flask.ext.login import login_user
    
    from models import User
    from app import app
    
    EMAIL_REGEX = re.compile(r'[^@]+@[^@]+\.[^@]+')
    
    @app.route('/login/<provider_name>')
    def login(provider_name):
          
      # для работый с адаптером WerkzeugAdapter понадобится объект response
      response = make_response()
    
      try:
      # перехватываем ошибки которые могут возникнуть при работе с oauth2 провайдером
    
        # если result = None значит процедура логина находится в процессе выполнения
        result = authomatic.login( WerkzeugAdapter( request, response ), provider_name )
    
        if result:
        # если получен результат oauth-логина
    
          if result.user:
          # и если имеется информация о пользователе 
    
            # получаем информацию о пользователе
            result.user.update()
            # получаем email
            email = result.user.email
    		
            if email and EMAIL_REGEX.match(email):
            # если указан правильный адрес
    					
              # находим соответствующего пользователя
              user = User.query.filter_by( email = email ).first()
    
              if user:
              # если пользователь зарегистрирован с системе
    
                # осуществляем вход в систему
                login_user( user )
                # делаем редирект на главную страницу сервиса
                return redirect( url_for( 'index' ) )
    
    # здесь отрабатываем все варианты отказа в регистрации
    # ...
    # ...
    
        else:
        # если результат oauth-логина еще не получен (result=None)
        # возвращаем объект response
         return response
    
    

    Основаня часть взаимодействия с oauth-провайдером сводится к одной строке:

    result = authomatic.login( WerkzeugAdapter( request, response ), provider_name )
    

    при первоначальном заходе на адресу: authomatic.login осуществляет редирект на указанного провайдера и передачу необходимых параметров;

    затем провайдер делает обратный редирект по тому же адресу и authomatic.login получает от провайдера требуемые данные.

    Как видите совсем несложно. Основную часть времени занимает не программирование, а регистрация своего приложения в каждом из используемых провайдеров.
    • +28
    • 24.7k
    • 6
    TheOnlyPage
    10.40
    Company
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 6

      +1
      Вот что-нибудь похожее только для аутентификации пользователей с моб.платформ через соц.сети/oauth2-провайдеров на своем сервере, т.к. с аутентификацией через браузер вроде особых проблем нет. А с моб.устройств у всех поголовно нужно токены проверять, т.к. элегантного решения я не нашел. Если у кого-то получилось это сделать красиво, поделитесь опытом)
        +1
        Для себя сделали серверную API прослойку между oauth2-провайдером и телефоном, очень удобно. Выглядит это примерно так: с мобильной лпатформы идет обращение к API серверу для авторизации с указанием желаемого провайдера, дальше, сервер делает запрос к АПИ провайдера, после чего, получив ссылку для авторизации, передает ее мобильной платформе, а она в свою очередь открывает ее во встроенном браузере. При успешной авторизации, присходит редирект на специальный URL приложения.
          0
          Исходничков в открытом доступе я так понимаю нет и не планируется?) Но за идею спасибо, я думал про такой вариант, но отказался в пользу менее удобного.
          Так как тут возникает проблема с тем, что пользователю нужно обязательно вводить свой логин/пароль от соц.сети, на что мне некоторые бета-тестеры сказали «мол это неудобно, сделай в пару кликов, у меня же стоит приложение от этой сети».
          И тут делема: либо делать универсально через oauth, но тогда пользователю вводить пароль, либо через sdk для каждой сети, что затратнее по времени, но удобнее конечному потребителю.
          Неужели в наше время для такой простой задачи приходится писать свои велосипеды вместо использования готового и протестированного решения. В гугле меня вроде не забанили, но найти такого я не смог.
        +3
        Стот упомянуть о существовании python-social-auth.readthedocs.org/en/latest/ — годами проверенное решение (разрабатывается с 2010-11-08).

          0
          Поддерживает ли Authomatic OpenID Connect?
          Страшно интересно потому, что хочется аутентифицировать пользователей не только через всех вышеперечисленных провайдеров, но, например, и через Azure AD и подобные, более корпоративные источники.
            +1
            Использую django-allauth.

            Умеет:
            — социальные регистрации/авторизации
            — авторизации/регистрации по имейлу или логину, или по обоим
            — если социалка не отдала имейл или другое обязательное поле, затребует его, а затем попросит подтвердить (в случае имейла) — все настраиваемо
            — авторизация по множеству имейлов, т.е. хочешь заходи по одному, хочешь по другому
            — смену имейлов
            — подтверждение имейлов
            — управление социальными аккаунтами — отключение, подключение
            — восстановление пароля
            — django 1.7

            Есть возможность:
            — указать какие формы использовать
            — использовать свои шаблоны путем простой перезаписи
            — приложение использует messages для вывода событий: вошел, ушел и прочее
            — сигналы и наследование «адаптеров» — это такой флоу процесса авторизации/регистрации

            По моему скромному мнению, это лучший код, который мне довелось читать: все комментировано, пеп, да тупо красиво. Код полностью обложен тестами.

            Есть одно «но»: до сих пор не могу полностью понять как оно работает %) Код так инкапсулирован, что без пол литра не разберешь.

            Only users with full accounts can post comments. Log in, please.