habrahabr

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

  • воскресенье, 5 октября 2014 г. в 03:10:51
http://habrahabr.ru/company/theonlypage/blog/239189/

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

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

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

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

  • Слабая связанность.
  • Компактный, но мощный интерфейс
  • Единственная, причем необязательная зависимость: библиотека pytyon-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 получает от провайдера требуемые данные.

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