Cоциальный логин (логин с использованием аккаунта Google+, Facebook и т.п.) все чаще встречается в мобильных и веб-приложениях. Не удивительно, это удобно. Пользователю не приходится возиться с логином и паролем. Не нужно ничего запоминать, затем вспоминать или восстанавливать. Не приходится разгадывать капчу. На мобильных устройствах ввод пароля крайне не желателен и формирует негативный опыт у пользователя. Владелец приложения получает свои плюсы: простая регистрация — большее количество пользователей, довольные пользователи — выше показатели конверсии. Наличие профиля пользователя уже на этапе регистрации, и как правило, много более достоверного и полного нежели формы запрашиваемые приложением.

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

Решают ли библиотеки все задачи?

Что хотят пользователь и владелец приложения



Как пользователь приложения, я хотел бы иметь возможность объединять несколько социальных аккаунтов в один. Определённо, я не хочу потерять доступ к приложению, потеряв доступ к социальному аккаунту. Или оказаться в ситуации, когда я вынужден продолжать использовать определённый социальный аккаунт лишь только по той причине, что он когда-то использовался для регистрации в приложении. Если использую несколько приложений, объединённых одним брендом (например, GMail и Google+), я ожидаю, что после логина или регистрации в одном из них мне так же будут доступны и другие, без необходимости повторного логина или регистрации. Если у меня появляются причины полагать, что доступ к моему аккаунту попал в чужие руки (возможно, после совершения логина в публичном месте), я хотел бы иметь возможность отозвать все ранее выпущенные токены доступа и, таким образом, заблокировать не желательный доступ к моему аккаунту.

Как владелец приложения, я не хотел бы тратить время на интеграцию социального логина каждый раз когда начинаю новый проект. Иметь рабочую версию сейчас, настройки позже, после запуска проекта. Если проект может быть выполнен в виде браузерного (фронтенд) или мобильного приложения, на их реализации и сконцентрировать свое внимание. Разворачивать серверное приложение и хранилище данных, только для целей социального логина, совсем не то, чем я хотел бы заниматься, работая над таким проектом. В то время как, не использовать серверное приложение для социального логина, означает отсутствие каких-либо гарантий того, что данные пользователя не будут разоблачены злоумышленнику, а токен доступа не будет подменен. В случае, с разработкой веб-сервиса (фронтенд + бэкенд), взаимодействие его компонентов должно быть простым и эффективным. Вероятно, я не захочу использовать токены выпущенные провайдером социального логина и требующие для валидации внешнего запроса к серверу провайдера. Могу захотеть выпустить собственные, на базе которых могут быть постороены SSO и Federated identity. Определённо, хочу иметь механизмы отзыва (аннулирования) токенов доступа. Наличие административного приложения могло бы упросить для меня доступ к информации о пользователях.

Аутентификация как сервис



Озвученные выше задачи могут быть решены в рамках веб-сервиса. В примерах ниже, используется веб-сервис PolyAuth. Цель которого — максимально упростить интеграцию аутентификации в приложение, за счёт единого API, стандартизированного формата данных профиля, необходимых инструментов и инфраструктуры. Доступно два, различных по применению, API для целей аутентификации и доступа к данным. Standalone Authentication API обеспечивает базовый функционал социального логина, быстрый старт и возможности, которые будут описаны ниже в примерах. Это API предоставляется в свободном доступе, без каких-либо платежей и лимитов на запросы. Main Authentication API обеспечивает расширенный функционал и нацелен на решение более широкого круга задач:

  • Быстрый старт. Будь то новый проект или существующий, интеграция не должна отнимать время. Рабочая версия сейчас, настройки позже.
  • Социальный логин. Логин с использованием Google, Facebook, и других провайдеров.
  • Стандартизированный профиль. Профиль пользователя в едином формате.
  • Много провайдеров — Один Пользователь. Объединение нескольких социальных аккаунтов в единый аккаунт пользователя.
  • Управление токенами. Выпуск, отзыв (аннулирование) и валидация токенов.
  • Single Sign-On (SSO). Когда приложений несколько, логин в одном позволяет пользователю получить доступ к ресурсам других без повторного логина.
  • Federated identity. Одно приложение может делегировать выполнение задач и получать ресурсы пользователя управляемые другими приложениями.
  • Поддержка безсерверных приложений. Для проектов которые могут быть выполнены в виде браузерного (фронтенд) или мобильного приложения, интеграция социального логина не должна накладывать дополнительных требований.
  • Административное приложение. Информация о пользователях и возможность совершения операций над ними должна быть доступна владельцу приложения в виде простого и понятного графического интерфейса.


Перед началом работы потребуется создать аккаунт и группу для будущих пользователей (realm). Указать URI приложения, куда пользователи будут отправлены после того как они делегируют доступ к их данным.

Аутентификация в браузерном приложении, веб-компоненты



Схема взаимодействия приложения с сервисом



С веб-компонентами, интеграция выглядит много проще, чем на схеме. Для их установки, используем Bower:

$ bower install --save 	polyauth-elements/polyauth-element 	polyauth-elements/polyauth-signin-pages 	fetch


Для импорта — необходимо включить следующие строки в <head> секцию HTML документа:

<script src='bower_components/fetch/fetch.js'></script>
<script src='webcomponentsjs/webcomponents-lite.min.js'></script>
<link rel='import' href='bower_components/polyauth-elements/polyauth-element.html'>


Для совместимости с версиями браузеров не имеющих реализации WebComponents и Fetch API импортируются полифилы. В примерах, так же, будут использоваться дополнительные веб-компоненты. Их перечень, как и весь исходный код примеров доступны на GitHub.

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



<template is='dom-repeat' items='[[endpoints]]'>
  <a href='[[item.authCodeURI]]'>
    <iron-icon icon$='[[item.icon]]'></iron-icon>
  </a>
</template>

<polyauth-authcode-endpoints
  apiv='v1'
  realm-id='REALM_ID'
  redirect-uri='REDIRECT_URI'
  objects='{{endpoints}}'>
</polyauth-authcode-endpoints>


После того как пользователь делегирует права доступа к его данным, он перенаправляется провайдером обратно в приложение со специальным кодом, который в дальнейшем может быть обменян на токен доступа (в соответствии с OAuth2 Authorization Code Grant). Токен доступа сохраняется приложением в локальном хранилище для повторного использования. Описанная схема полностью реализована в веб-компоненте polyauth-signin-pages, который кроме прочего, прячет форму аутентификации.

<polyauth-signin-pages
  apiv='v1'
  realm-id='REALM_ID'
  access-token='{{token}}'
  auto>

  <section signed-out>
    <!-- Этот блок увидят пользователи,
        которые еще не выполнили вход -->

    <template is='dom-repeat' items='[[endpoints]]'>
      <a href='[[item.authCodeURI]]'>
        <iron-icon icon$='[[item.icon]]'></iron-icon>
      </a>
    </template>
  </section>

  <section signed-in>
    <!-- Этот блок увидят пользователи,
         которые выполнили вход -->
  </section>

</polyauth-signin-pages>


Имея токен доступа, можно получить профиль пользователя и отобразить его аватар и сообщение приветствия:



<iron-image src='[[profile.data.info.image]]'></iron-image>
<div>Hello, <span>[[profile.data.info.name]]</span>!</div>

<polyauth-profile
  apiv='v1'
  access-token='[[token]]'
  object-id='me'
  object='{{profile}}'
  auto>
</polyauth-profile>


Для кнопки выхода, потребуется одним HTML тегом больше.

<button polyauth-sign-out>Sign Out</button>


Объединить несколько аутентификационных записей под одним аккаунтом пользователя, не многим сложнее:



<polyauth-user
  apiv='v1'
  access-token='[[token]]'
  object-id='me'
  fields='["profile", "auth"]'
  object='{{user}}'
  auto>
</polyauth-user>

<polyauth-user-authlinks
  id='authLinksProxy'
  apiv='v1'
  realm-id='REALM_ID'
  redirect-uri='REDIRECT_URI'
  access-token='[[token]]'
  user-id='me'
  objects='[[user.auth]]'
  objects-proxy='{{authLinks}}'>
</polyauth-user-authlinks>

<template is='dom-repeat' items='[[authLinks]]'>
  <iron-icon icon$='[[item.icon]]'></iron-icon>
  <paper-toggle-button
    checked='[[!item.removed]]'
    on-change='_handleAuthLink'>
  </paper-toggle-button>
</template>


Для этой задачи потребуется JavaScript функция-обработчик события:

_handleAuthLink: function(e) {
    this.$.authLinksProxy.handle(e.model.index);
}


Аутентификация в браузерном приложении, JavaScript



JavaScript библиотека может быть установлена с помощью Bower:

$ bower install --save fetch polyauth


Для импорта — необходимо включить следующие строки в <head> секцию HTML документа:

<script src='bower_components/fetch/fetch.js'></script>
<script src='bower_components/polyauth/polyauth.js'></script>


Выполнить логин и получить профиль пользователя можно следующим образом:

// Перенаправление пользователя на страницу провайдера
window.location.href =
  PolyAuth.authCodeURI(REALM_ID, {
    apiv: 'v1',
    key: 'oauth2.google-plus',
    redirectURI: REDIRECT_URI
  }

// Получение профиля пользователя
PolyAuth
  .signIn(REALM_ID)
  .then(function(resp) {
    PolyAuth
      .fetch(PolyAuth.api(resp.accessToken, 'v1').profile('me').get())
      .then(function(object) {
          console.log(resp);
      });
   });

// {
//   "id": "8c63a8cb-b3dd-4772-b133-169f4b3d5e47",
//   "data": {
//       "info": {
//         "name": "John Doe",
//         "last_name": "Doe",
//         "first_name": "John",
//         "email": "john@example.com",
//         "image": "https://example.com/photo.jpg",
//         "uri": "https://plus.google.com/1aeb832ae4d6"
//       }
//   }
// }


В этом и ранее приведённых примерах с веб-компонентами, профиль пользователя сохраняется в облаке, а для приложения выпускается токен доступа управляемый сервисом аутентификации. Такой токен может быть отозван пользователем или владельцем приложения, передан другому приложению, валидирован локально, без внешних запросов.

Расширенный доступ к данным пользователя



Для случаев, когда информации профиля пользователя не достаточно или требуется доступ к API провайдера, Standalone Authentication API обеспечивает унифицированный интерфейс для работы с провайдерами.

Схема взаимодействия приложения с сервисом



// Перенаправление пользователя на страницу провайдера
window.location.href =
  PolyAuth.authCodeURI(REALM_ID, {
    apiv: 'v1',
    key: 'oauth2.google-plus',
    redirectURI: REDIRECT_URI,
    op: 's/token'
  }

// Получение токена доступа
var qs = PolyAuth.QS.parse();

var req =
  PolyAuth
    .api('v1')
    .realm(REALM_ID)
    .auth(qs.key)
    .standaloneToken({code: qs.code, secret: REALM_SECRET});

PolyAuth
    .fetch(req)
    .then(function(resp) {
          console.log(resp);
    });
    
// {
//   "access_token": "eyPae7femio7jo9re4Cimish...",
//   "expires_in": 3575,
//   "id_token": "eyciO6hbGhJd5NiUjIIsImtp...",
//   "token_type": "Bearer"
// }


Запрос на получение токена доступа, управляемого провайдером, должен содержать Realm’s Secret.

Особенностью Standalone Authentication API является то, что профиль пользователя не сохраняется в облаке и приложение получает токен доступа управляемый провайдером (не сервисом) аутентификации.

Аутентификация без ограничений и лимитов



С использованием Standalone Authentication API может быть так же получен и профиль пользователя. При этом токен доступа провайдера не будет разоблачён приложению. Таким образом, может быть достигнута гарантия безопасности персональных данных пользователя даже в не защищённой среде (браузерные и мобильные приложения). Эта функциональность может быть полезна в случаях, когда от социального логина требуется только его базовый функционал.

Схема взаимодействия приложения с сервисом



// Перенаправление пользователя на страницу провайдера
window.location.href =
  PolyAuth.authCodeURI(REALM_ID, {
    apiv: 'v1',
    key: 'oauth2.google-plus',
    redirectURI: REDIRECT_URI,
    op: 's/profile'
  }

// Получение профиля пользователя
var qs = PolyAuth.QS.parse();

var req =
  PolyAuth
    .api('v1')
    .realm(REALM_ID)
    .auth(qs.key)
    .standaloneProfile({code: qs.code});

PolyAuth
    .fetch(req)
    .then(function(resp) {
          console.log(resp);
    });
    
// {
//   "info": {
//     "gender": "male",
//     "name": "John Doe",
//     "last_name": "Doe",
//     "first_name": "John",
//     "gender": "male",
//     "email": "john@example.com",
//     "image": "https://example.com/photo.jpg",
//     "uri": "https://plus.google.com/1aeb832ae4d6"
//   },
//   "uid": "106276572039433743690"
// }
О подходе, аутентификации как сервиса

Проголосовало 88 человек. Воздержалось 56 человек.

О приложениях, над которыми работаете

Проголосовало 108 человек. Воздержалось 55 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Комментарии (6)


  1. FreeMind2000
    04.08.2015 20:14

    Я параноик и никогда на сторонние/левые сайты через соц.аккаунты не вхожу (и другим не советую) — только логин пароль специально для данного сайта.
    Почему?

    1. Допустим я через поисковик захожу на сайт злоумышленника, который при регистрации хочет украсть мои данные соц.аккаунта.
    2. Вижу перед собой кнопочки входа через ВК и т.п.
    3. Нажимаю на них (и если в браузере еще не было входа в ВК) — вижу поддельную ВК форму ввода логин/пароль
    4. Ленюсь/не знаю, что надо проверять строку url браузера — честно ввожу свои данные и дарю их злоумышленнику.
    5. Всё, миссия выполнена :)

    Или я в чем-то не прав?


    1. shasoft
      04.08.2015 20:44

      Зачастую вы уже залогинены в социальной сети и все что вам нужно — это нажать кнопку «Разрешить» и происходит вход. Т.е. никакого ввода логина/пароля нет.


    1. aenesterov
      04.08.2015 21:24

      Это какая-то неправильная паранойя. Если не смотрите на адресную строку браузера при входе, по той же схеме, можете потерять и Ваши уникальные логин и пароль.


      1. FreeMind2000
        04.08.2015 21:35
        +1

        Зачастую… но не всегда, в этом-то и проблема.
        Попробуйте разлогинтесь из ВК и войти через кнопку ВК на хабре — Сам ВК предлагает ввести/логин пароль и обычный юзер на url редко смотрит ;)

        А после того, как вы подарили свой соц.аккаунт злоумышленнику, что ему мешает попытаться автоматически под ним зайти на все более менее популярные сервисы и утащить все ваши данные оттуда?
        Потеряв один аккаунт — вы теряете все свои данные.

        В случае с логин/пароль для каждого сайта — вы отдаете злоумышленнику только эти данные, но… вы ведь так и задумывали (регистрация все-таки), поэтому никаких данных не теряете.


        1. FreeMind2000
          04.08.2015 22:05

          Если не смотреть на url — то можно только попасть на фейковые сайты, которые в поисковой выдаче выше реальных, ну или через спам-ссылку (угроза довольно редко возникает).

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


        1. aenesterov
          04.08.2015 22:05

          Я понимаю о чём Вы говорите. Но здесь проблема не в социальном логине. Если пользователь не думает о своей безопасности — он потеряет свои аккаунты и данные вместе с ними. Пусть не за одну итерацию, а за несколько, итог один. Другими словами, не умеешь управлять автомобилем, не садись за руль. Безопасность пользователя в его руках, что с социальным логином, что с парой логин и пароль.