Package: django-loginza
Django-приложение, обеспечивающее работу с сервисом авторизации Loginza (loginza.ru)УстановкаУстановка производится с помощьюpip:$ pip install django-loginzaИли добавлением следующей строчки вproject_name/requirements.txt:django-loginzaА затем установкой черезpip:$ pip install -r project_name/requirements.txtПоследняя актуальная версия доступна врепозитории GitHub.Для корректной работы приложения необходимо, чтобы так же был установлено приложенияdjango.contrib.auth,django.contrib.sessionsиdjango.contrib.sites.После этого, необходимо добавить приложениеloginzaвINSTALLED_APPSи добавить бэкэнд авторизации -loginza.authentication.LoginzaBackendвAUTHENTICATION_BACKENDS. В общем случае, бэкэнды
авторизации после добавления нового, будут выглядеть так:AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'loginza.authentication.LoginzaBackend',
)В этом случае, можно будет использовать как стандартную форму авторизации по логину и паролю
(например, для доступа в админскую панель), так и loginza-авторизацию.Также, следует добавить вTEMPLATE_CONTEXT_PROCESSORSстрочкуdjango.core.context_processors.request.После добавления приложения, необходимо установить необходимые таблицы в БД (выполнитьpython manage.py syncdbв корне проекта).Далее, нужно зарегистрировать ссылки приложения в проекте. В общем случае,
необходимо добавить следующий элемент вurlpatternsпроекта вurls.py:(r'^loginza/', include('loginza.urls')),Чтобы при авторизации через loginza вас не перенаправляло не пойми куда (например, example.com) -
следует в админке, в настройках сайтов указать правильный домен.ИспользованиеПриложение можно условно разделить на три составляющих:шаблонные теги, для отображения виджета авторизации на страницесигналы, позволяющие другим приложениям взаимодействовать с даннымвнутренняя логика приложенияЭтот документ рассматривает только первые две составляющие.Шаблонные тегиДля того, чтобы отобразить виджет авторизации в шаблоне, сначала необходимо загрузить тэги:{% load loginza_widget %}После этого, становятся доступны следующие теги:loginza_iframe- встраиваемый виджета авторизации Loginza (спаренная форма авторизации)loginza_button- кнопка виджета Loginzaloginza_icons- набор иконок провайдеровloginza_string- строка (ссылка)Примеры отображения виджетов можно посмотреть на страницеПримеры интеграции Loginza в форму авторизации сайта.Для всех тэгов, кромеloginza_iframeнеобходим обязательный параметр caption.
Дляloginza_buttonон используется для атрибутовaltиtitleизображения кнопки,
дляloginza_icons- текст, перед набором иконок (например,Войти используя:),
дляloginza_string- собственно сама строка.Так же, для всех виджетов доступны следующие именованные параметры:lang- язык виджетаproviders_set- доступные кнопки и порядок провайдеровprovider- провайдер авторизации по умолчаниюНапример:{% loginza_iframe providers_set="google,facebook,twitter" lang="en" %}Более подробно об этих параметрах можно прочитать вРуководстве по Loginza.API.Дополнительно, дляloginza_iframeдоступны параметрыwidthиheight,
которыми можно задать размер виджета (по умолчанию 359 x 300 px).В общем случае шаблон, отвечающий за авторизацию, будет выглядеть следующим образом:{% load loginza_widget %}
{% if user.is_authenticated %}
  Добро пожаловать, {{ user }}
{% else %}
  {% loginza_button "Войти через Loginza" %}
{% endif %}СигналыПриложение предоставляет следующие сигналы:created- создана новая связка между идентификатором Loginza и пользователем Djangoerror- во время авторизации произошла ошибкаauthenticated- пользователь успешно авторизован (authenticated) и готов быть залогиненlogin_required- декоратор login_required обнаружил, что пользователь не авторизованБолее подробно о сигналах и их параметрах можно прочитать в их документации к сигналам вsignals.pyприложения.Примерviews.pyвспомогательного приложенияusers, использующего сигналы приложенияloginza:# -*- coding:utf-8 -*-
from django import http
from django.contrib import messages, auth
from django.shortcuts import redirect, render_to_response
from django.core.urlresolvers import reverse
from django.template.context import RequestContext

from .forms import CompleteReg

from loginza import signals, models
from loginza.templatetags.loginza_widget import _return_path


def loginza_error_handler(sender, error, **kwargs):
    messages.error(sender, error.message)

signals.error.connect(loginza_error_handler)

def loginza_auth_handler(sender, user, identity, **kwargs):
    try:
        # it's enough to have single identity verified to treat user as verified
        models.UserMap.objects.get(user=user, verified=True)
        auth.login(sender, user)
    except models.UserMap.DoesNotExist:
        sender.session['users_complete_reg_id'] = identity.id
        return redirect(reverse('users.views.complete_registration'))

signals.authenticated.connect(loginza_auth_handler)

def loginza_login_required(sender, **kwargs):
    messages.warning(sender, u'Функция доступна только авторизованным пользователям.')

signals.login_required.connect(loginza_login_required)


def complete_registration(request):
    if request.user.is_authenticated():
        return http.HttpResponseForbidden(u'Вы попали сюда по ошибке')
    try:
        identity_id = request.session.get('users_complete_reg_id', None)
        user_map = models.UserMap.objects.get(identity__id=identity_id)
    except models.UserMap.DoesNotExist:
        return http.HttpResponseForbidden(u'Вы попали сюда по ошибке')
    if request.method == 'POST':
        form = CompleteReg(user_map.user.id, request.POST)
        if form.is_valid():
            user_map.user.username = form.cleaned_data['username']
            user_map.user.email = form.cleaned_data['email']
            user_map.user.save()

            user_map.verified = True
            user_map.save()

            user = auth.authenticate(user_map=user_map)
            auth.login(request, user)

            messages.info(request, u'Добро пожаловать!')
            del request.session['users_complete_reg_id']
            return redirect(_return_path(request))
    else:
        form = CompleteReg(user_map.user.id, initial={
            'username': user_map.user.username, 'email': user_map.user.email,
            })

    return render_to_response('users/complete_reg.html',
                              {'form': form},
                              context_instance=RequestContext(request),
                              )Примерforms.pyвспомогательного приложенияusers:# -*- coding:utf-8 -*-
from django import forms
try:
    from django.contrib.auth import get_user_model
        except ImportError: # django < 1.5
    from django.contrib.auth.models import User
else:
    User = get_user_model()


class CompleteReg(forms.Form):

    username = forms.RegexField(label=u'Имя пользователя', max_length=30, min_length=4,
                                required=True, regex=r'^[\w.@+-]+$')
    email = forms.EmailField(label=u'Email', required=True)


    def __init__(self, user_id, *args, **kwargs):
        super(CompleteReg, self).__init__(*args, **kwargs)
        self.user_id = user_id

    def clean_username(self):
        if self.cleaned_data['username']:
            try: u = User.objects.exclude(id=self.user_id).get(username=self.cleaned_data['username'])
            # if username is unique - it's ok
            except User.DoesNotExist: u = None

            if u is not None:
                raise forms.ValidationError(u'Пользователь с таким именем уже зарегистрирован')
        return self.cleaned_data['username']

    def clean_email(self):
        if self.cleaned_data['email']:
            try: u = User.objects.exclude(id=self.user_id).get(email=self.cleaned_data['email'])
            # if email is unique - it's ok
            except User.DoesNotExist: u = None

            if u is not None:
                raise forms.ValidationError(u'Пользователь с этим адресом уже зарегистрирован')
        return self.cleaned_data['email']Примерurls.pyвспомогательного приложенияusers:from django.conf.urls.defaults import *

from .views import complete_registration


urlpatterns = patterns('',
    url(r'^complete_registration/$', complete_registration, name='users_complete_registration'),
    url(r'^logout/$', 'django.contrib.auth.views.logout', name='users_logout'),
)Для того, чтобы пример выше работал корректно, необходимо так же вsettings.pyпроекта добавить
следующие настройки (подробнее читайте в разделеНастройки):# can't use reverse url resolver here (raises ImportError),
# so we should carefully control paths
LOGINZA_AMNESIA_PATHS = ('/users/complete_registration/',)Так же добавить приложениеusersвINSTALLED_APPS, а затем вurls.pyпроекта
добавить следующее:url(r'^users/', include('users.urls')),НастройкиВ приложении доступны следующие настройки:LOGINZA_DEFAULT_LANGUAGE- язык по умолчанию, если параметрlangне задан для виджета явно.
Выбирается на основеLANGUAGE_CODEпроекта.LOGINZA_DEFAULT_PROVIDERS_SET- набор провайдеров, используемых по умолчанию,
если параметрproviders_setне задан. Формат - имена провайдеров через запятую,
например ‘facebook,twitter,google’.None- все доступные провайдеры.LOGINZA_DEFAULT_PROVIDER- провайдер, используемый по умолчанию,
если параметрproviderне задан для виджета явно.None- не задан.LOGINZA_ICONS_PROVIDERS- иконки провайдеров, отображаемые виджетом loginza_icons,
по умолчанию все доступные. Используется, только если параметрproviders_set`не задан для виджета явно и
настройкаLOGINZA_DEFAULT_PROVIDERS_SETне задана. Формат - имена провайдеров через запятую,
например ‘facebook,twitter,google’.LOGINZA_PROVIDER_TITLES- заголовки провайдеров, используемые для изображений виджетаloginza_icons. Формат - словарь с ключами именами провайдеров, и значениями - заголовками, например
{‘google’: u’Корпорация добра’, ‘twitter’: u’Щебетальня’, ‘vkontakte’: u’Вконтактик’}LOGINZA_DEFAULT_EMAIL- адрес электронной почты, используемый для новых пользователей, в случае,
если Loginza не предоставила, таковой. По умолчанию -‘user@loginza’. В случае, когда в данных отсутствует
имя пользователя, идентификатор (слева от @) адреса электронной почты используется в качестве
имени пользователя по умолчанию.LOGINZA_AMNESIA_PATHS- список или кортеж путей, которые не будут запоминаться для возврата.
Например, как показано в примере выше, страница завершения регистрации не запоминается, для того,
чтобы после успешной авторизации пользователь был возвращен на страницу, с которой авторизация началась,
а не на пустую страницу завершения регистрации.LOGINZA_BUTTON_IMG_URL- ссылка на изображение, используемое для виджета Кнопка. По умолчанию
изображение загружается с сайта loginza.ru.LOGINZA_ICONS_IMG_URLS- словарь со ссылками на иконки провайдеров авторизации, используемых для
виджета Иконки. По умолчанию изображения загружаются с сайта loginza.ru.LOGINZA_IFRAME_WIDTH- ширина встраевомого виджета авторизации (строка, использвется как есть,
по умолчанию 359px).LOGINZA_IFRAME_HEIGHT- высота встраевомого виджета авторизации (строка, использвется как есть,
по умолчанию 300px).LOGINZA_WIDGET_ID- ID виджета Loginza (см. в секцииМой виджет Loginza).LOGINZA_API_SIGNATURE- Секретный ключ виджета Loginza.Дополнительные возможностиПриложение предоставляет модифицированный декоратор@login_required. От оригинального декоратораdjango.contrib.auth.decorators.login_requiredон отличается тем, что вместо перенаправления не
авторизованных пользователей на страницу авторизации срабатывает перенаправление на предыдущую страницу.
Декоратор может быть полезен сайтам, использующим только Loginza-авторизацию и не имеющим отдельную страницу
авторизации. Так же, при срабатывании декоратора для не авторизованных пользователей, посылается сигналloginza.signals.login_required, присоединившись к которому можно, например, уведомить пользователя
о причине возврата на предыдущую страницу (как это показано в примере), и вернуть объект HttpRespose,
если необходимо выполнить действие отличное, от возвращения пользователя на предыдущую страницу.Автор:Владимир ГарвардтБлагодарности:Ивану Сагалаеву, Юрию Юревичу, Денису Веселову