Иллюстрированное руководство по OAuth и OpenID Connect | ProHoster

Что мы хотим получить в итоге

Мы реализуем OpenId Connect Implicit Flow, который рекомендован для JavaScript-приложений, в браузере, в том числе для SPA. В процессе мы чуть глубже, чем это обычно делается в пошаговых руководствах, обсудим разные значимые настройки. Затем мы посмотрим, как работает наша реализация с точки зрения протокола OpenId Connect, а также изучим, как имплементация соотносится с протоколом.

IdentityServer

Создайте solution с пустым проектом, в качестве платформы выберите ASP.NET Core 1.1.

Установите такие NuGet-пакеты

Install-Package Microsoft.AspNetCore.Mvc -Version 1.1.3
Install-Package Microsoft.AspNetCore.StaticFiles -Version 1.1.2
Install-Package IdentityServer4 -Version 1.5.2

Версии пакетов здесь значимы, т.к. Install-Package по умолчанию устанавливает последние версии. Хотя авторы уже сделали порт IdentityServer на Asp.NET Core 2.0 в dev-ветке, на момент написания статьи, они ещё не портировали Quickstart UI. Различия в коде нашего примера для .NET Core 1.1 и 2.0 невелики.

Измените метод MainProgram.cs так, чтобы он выглядел следующим образом

Api

Данный проект — игрушечный сервер API с ограниченным доступом.

Добавьте в solution ещё один пустой проект Api, в качестве платформы выберите ASP.NET Core 1.1. Т.к. мы не собираемся создавать полноценное веб-приложение в данном проекте, а лишь легковесный веб-сервис, отдающий JSON, ограничимся лишь MvcCore middleware вместо полного Mvc.

Добавьте нужные пакеты, выполнив эти команды в Package Manager Console

Install-Package Microsoft.AspNetCore.Mvc.Core -Version 1.1.3
Install-Package Microsoft.AspNetCore.Mvc.Formatters.Json -Version 1.1.3
Install-Package Microsoft.AspNetCore.Cors -Version 1.1.2
Install-Package IdentityServer4.AccessTokenValidation -Version 1.2.1

Начнём с того, что добавим нужные настройки Kestrel в Program.cs

Client

Этот проект фактически не содержит значимой серверной части. Весь серверный код — это просто настройки веб-сервер Kestrel, с тем чтобы он отдавал статические файлы клиента.

Так же, как и прошлых 2 раза добавьте в решение пустой проект, назовите его Client.

Установите пакет для работы со статическими файлами.

Install-Package Microsoft.AspNetCore.StaticFiles -Version 1.1.2

Измените файл Program.cs

Access_token обновляется

Давайте теперь добавим в app.js в объект config код, так чтобы получилось

Access_token устаревает

Дождитесь устаревания access_token, нажмите кнопку Call API.

API будет вызван! Это вызвано тем, что IdentityServer использует middleware Asp.Net Core, который использует понятие ClockSkew. Это нужно для того, чтобы всё в целом работало в случае если часы на клиенте и разных серверах несколько неточны, например, не возникали ситуации вроде токена, который был выпущен на период целиком в будущем. Значение ClockSkew по умолчанию 5 минут.

Теперь подождите 5 минут и убедитесь, что вызов API теперь возвращает 401 (Unathorized).

Замечание В клиентском приложении может быть полезно явно обрабатывать ответы с кодом 401, например пытаться обновить access_token.

Authorization code grand

Является одним из наиболее распространённых типов разрешения, поскольку он хорошо подходит для серверных приложений, где исходный код приложения и секрет клиента не доступны посторонним.

Client credentials

Начнем разбор с самой простой схемы. Этот способ придуман для межсерверного взаимодействия. У нас есть два сервера API1 и API2, и им надо как-то общаться.

  1. API 1 идет в авторизационный сервер передает туда client_id и client_secret.

Client id и secret

Задолго до того, как вы разрешили Terrible Pun of the Day получить доступ к контактам, Client и Authorization Server установили рабочие отношения. Authorization Server сгенерировал Client ID и Client Secret (иногда их называют App ID и App Secret) и отправил их Client’у для дальнейшего взаимодействия в рамках OAuth.

Иллюстрированное руководство по OAuth и OpenID Connect«— Привет! Я хотел бы работать с тобой! — Да не вопрос! Вот твои Client ID и Secret!»

Название намекает, что Client Secret должен держаться в тайне, чтобы его знали только Client и Authorization Server. Ведь именно с его помощь Authorization Server подтверждает истинность Client’а.

Happy path

Посмотрим, какие действия соответствуют первым двум шагам спецификации.1. Клиент готовит запрос на аутентификацию, содержащий нужные параметры запроса.2. Клиент шлёт запрос на аутентификацию на сервер авторизации.Кликните на кнопку Login.

Id token — это jwt

ID Token — это особым образом отформатированная строка символов, известная как JSON Web Token или JWT (иногда токены JWT произносят как «jots»). Сторонним наблюдателям JWT может показаться непонятной абракадаброй, однако Client может извлечь из JWT различную информацию, такую как ID, имя пользователя, время входа в учетную запись, срок окончания действия ID Token‘а, наличие попыток вмешательства в JWT. Данные внутри ID Token‘а называются заявками[claims].

Иллюстрированное руководство по OAuth и OpenID Connect

В случае OIDC также имеется стандартный способ, с помощью которого Client может запросить дополнительную информацию о личности [identity] от Authorization Server‘а, например, адрес электронной почты, используя Access Token.

Id_token устаревает

Если access_token предназначается для ресурса API и ресурс обязан проверить его валидность, в том числе не устарел ли токен, при обращении к нему, то id_token предназначен именно для самого клиентского приложения. Поэтому и проверка должна проводиться на клиенте js-клиенте. Хорошо описано тут.

Implicit grant

Теперь у нас сайт без бэкенда – SPA.

Logout

Отправляется GET-запрос на end_session_endpoint

В ответ нас перенаправляют на страницу, содержащую данные о логауте для пользователя.

Oauth

Вообще OAuth – не для того преназначена, чтобы моментально проходить аутентификацию, очень хорошо про OAuth расписано

. Но(!) аутентификация там есть, мы этим и воспользуемся. Для начала выберем героев:

Быстрый старт с openid

Добрый день, друзья.

Сегодня я хочу поделиться своим опытом внедрения авторизации по openID на своем книжном сайте «Мои книги». Статья рассчитана на начинающих, поэтому вряд ли заинтересует тех, кто уже знает все нюансы этой технологии. Основная ее цель – ответить на вопрос: «да, это удобно, но как же мне сделать такое в моем проекте?!!»

Быстрый старт

Желания ковыряться в больших библиотеках у меня не возникло, так что за основу был взят простой класс Simple OpenID PHP Class.

Для начала отсюда нам понадобятся всего два скрипта: class.openid.php и openid-example.php. Первый — сам класс для работы с openID, второй — образчик его использования, который дальше можно дорабатывать под свои цели. Приятно, что многое прокомментировано. По идее, при правильных настройках сервера тестовый скрипт должен работать уже через 5 минут. Из которых 4 минуты ушло, как ни странно, на выяснение того, что же такое openID-идентификатор.

Список openID

OpenID — замечательная технология. Но скажите — кто придумал, что в роли своего openID пользователь должен указывать что-то вроде

http://id.rambler.ru/users/{логин}/

? Они хотят, чтобы я набирал

это

, да еще и

каждый раз

вместо пары логин-пароль?! Извините, мне проще зарегистрироваться как обычно. Это во-первых. Во-вторых, никакого единообразия в записи идентификаторов я не заметил: каждый провайдер придумывает такой вид URL, какой ему заблагорассудится. Посмотрите сами:

http://openid.yandex.ru/{логин}
http://openid.mail.ru/mail/{логин}
http://{логин}.myopenid.com/
http://{логин}.wordpress.com/
http://{логин}.blogspot.com/
http://{логин}.livejournal.com/
http://www.liveinternet.ru/users/{логин}
http://id.rambler.ru/users/{логин}/

В-третьих, почему-то эти адреса никак не фигурируют на страницах openID-провайдеров. Да, все заявляют об их поддержке, но попробуйте, скажем, найти этот URL на странице

http://openid.mail.ru

. Вот именно. Мне тоже пришлось на полдня стать Шерлоком Холмсом, прежде чем я составил свой список.

Удобство или произвольная openID-авторизация

Из сказанного выше вытекает такой момент: дать пользователю возможность вводить произвольный openID URL, или же ограничить его небольшим списком основных провайдеров? Плюс первого варианта: можно авторизоваться с любого сервера. Минус: вынуждаем пользователя запоминать и вводить этот длинный и непонятный адрес. Плюс второго варианта: удобство ввода (выбираем сервер из списка, вводим только логин). Минус: принудительно ограничиваем пользователя только определенным списком серверов авторизации.

Как поступить здесь — каждый решает самостоятельно. Я выбрал второй путь. В конце концов, сложно найти обычного пользователя, у которого нет учетки на Яндексе, Рамблере, ЖЖ или Mail.ru (Гугл в этом плане сильно отличился — я честно пытался понять, как у них сделана openID, но так и не осилил. Если кто-то может объяснить — пишите в комментариях). Так что я составил список основных серверов, из которых пользователь выбирает свой ( посмотреть в действии ).

А дальше?

Ну что ж, авторизация работает, нас перенаправляет на нужный сервер и обратно, скрипт радостно выдает «VALID». Что делать дальше? Дальше необходима еще одна страница, на которой пользователю будет предложено дозаполнить свой профиль. Допустим, мне от пользователя нужен регион и город проживания. E-mail тоже передают не все провайдеры. В-общем, нужно смотреть по ситуации. После того, как профиль заполнен и создан — авторизуем, и дальше пользователь работает как обычно.

Подводные камни

Пока прикручивал openID на своем сайте, пришлось потратить немало нервных клеток. Во-первых, то, что работает на локальном сервере, необязательно будет работать у хостера (даже при наличии curl). Пришлось пробовать другие версии класса (по самой первой ссылке в статье доступны еще два варианта — class.openid.v2.php и class.openid.v3.php).

Еще одним полезным методом в классе является GetAttribute(), которая позволяет взять параметры профиля с openID-сервера (e-mail, полное имя, пол и т.д. – например, вот так: $openid->GetAttribute(’email’) ). Правда, во второй и третьей версии класса он куда-то исчез, так что нужно добавить:

function GetAttribute($val)
{
return $_GET[«openid_sreg_».$val];
}

В целом, можно считать это джентльменским минимумом, чтобы запустить у себя в проекте авторизацию по openID. Буду признателен за дополнения и замечания.

Взгляд в будущее


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

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

OAuth

Вконтакте

Иллюстрированное руководство по OAuth и OpenID Connect | ProHoster

Вконтакте как всегда выделился, чтобы написать пошагово как что сделать, чтобы было как в фейсбуке – они просто дали свой виджет и написали «скажи куда послать данные». Виджету надо передать ApplicationID и всё. Вконтакте не передает вообще никакой email – зато скидывает ссылку на аватарку и фоточку пользователя. Javacript:

VK.init({ apiId: vkontakteAppId });
VK.Widgets.Auth("vk_auth", { width: "210px", authUrl: '/vkontakte' });

А в нужном контроллере получаем:

Дамы и господа, встречайте: oauth 2.0

— это стандарт безопасности, позволяющий одному приложению получить разрешение на доступ к информации в другом приложении. Последовательность действий для выдачи разрешения [permission] (или согласия[consent]) часто называют авторизацией[authorization] или даже делегированной авторизацией[delegated authorization].

В качестве примера представим, что вы обнаружили сайт с названием «Неудачный каламбур дня» [Terrible Pun of the Day] и решили зарегистрироваться на нем, чтобы ежедневно получать каламбуры в виде текстовых сообщений на телефон. Сайт вам очень понравился, и вы решили поделиться им со всеми знакомыми. Ведь жуткие каламбурчики нравятся всем, не так ли?

Иллюстрированное руководство по OAuth и OpenID Connect«Неудачный каламбур дня: Слышали о парне, который потерял левую половину тела? Теперь он всегда прав!» (перевод примерный, т.к. в оригинале своя игра слов — прим. перев.)

Понятно, что писать каждому человеку из контакт-листа не вариант. И, если вы хотя бы чуточку похожи на меня, то пойдете на всё, чтобы избежать лишней работы. Благо Terrible Pun of the Day может сам пригласить всех ваших друзей! Для этого лишь нужно открыть ему доступ к электронной почте контактов — сайт сам отправит им приглашения (OAuth рулит)!

Иллюстрированное руководство по OAuth и OpenID Connect

Делаем дело и работаем работу

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

, а мы давайте попробуем сделать свою систему авторизации через OpenID (например, для блога) на Python, с преферансом и пианистками.


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

Projects

Запрос ключа доступа

Для запроса ключа доступа клиент делает POST запрос к конечной точке IdentityServer4 со следующим заголовком

'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Expect': '100-continue'

и передавая следующие параметры:

Инструменты

Основные авторы обеих библиотек — Брок Аллен и Доминик Брайер.

История возникновения oauth

Авторизацией через социальные сети никого уже не удивишь. Нажимаешь кнопку соц сети, вжух и ты авторизовался на новом сайте. Сайт получил твоё ФИО, фотку и прочие данные. Но так было не всегда.

Как это работает

Запускать проекты рекомендую так: запускаете консоль, переходите в папку проекта, выполняете команду dotnet run. Это позволит видеть что IdentityServer и другие приложения логируют в консоль.

Запустите вначале IdentityServer и Api, а затем и Client.

Немного об openid connect

Если Вы понимаете OpenId Connect, можете начинать читать со следующей части.

Полезные ссылки

  1. Хороший туториал.
  2. Официальные примеры IdentityServer4
  3. Официальные примеры oidc-client.
  4. Тут можно почитать про политики авторизации в ASP.NET Core. Заодно стоит прочитать и это.
  5. В этой статье описано как использовать атрибут Authorize со списками ролей совместно с IdentityServer.
  6. Здесь описано почему в стандарте OpenId Connect 2 токена — id_token и access_token вместо одного.
  7. В процессе подготовки этой статьи вышла эта статья по реализации OpenId Connect в ASP.NET Core.

Пользователь на даёт разрешение на api1

В токене теперь нет claim api1

"scope": [
    "openid",
    "profile"
],

При попытке вызвать Api нам теперь возвращают 401 (Unathorized).

Пользователь не даёт разрешения на профиль

Скопируйте закодированный id_token из одноимённого параметра URL ответа и убедитесь, что теперь в него не входят claims, которые входят в стандартный scope profile.

Claims, которые входят в стандартный scope profile можно посмотреть тут.

При этом вызвать API получится.

Поток oauth

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

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

  • Resource Owner:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Это вы! Вы владеете своими учетными данными, своими данными и управляете всеми действиями, которые могут быть произведены с вашими аккаунтами.

  • Client:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Приложение (например, сервис Terrible Pun of the Day), которое хочет получить доступ или выполнить определенные действия от имени Resource Owner‘а.

  • Authorization Server:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Приложение, которое знает Resource Owner‘а и в котором у Resource Owner‘а уже есть учетная запись.

  • Resource Server:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Программный интерфейс приложения (API) или сервис, которым Client хочет воспользоваться от имени Resource Owner‘а.

  • Redirect URI:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Ссылка, по которой Authorization Server перенаправит Resource Owner‘а после предоставления разрешения Client‘у. Иногда ее называют «Возвратным URL» («Callback URL»).

  • Response Type:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Тип информации, которую ожидает получить Client. Самым распространенным Response Type‘ом является код, то есть Client рассчитывает получить Authorization Code.

  • Scope:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Это подробное описание разрешений, которые требуются Client‘у, такие как доступ к данным или выполнение определенных действий.

  • Consent:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Authorization Server берет Scopes, запрашиваемые Client‘ом, и спрашивает у Resource Owner‘а, готов ли тот предоставить Client‘у соответствующие разрешения.

  • Client ID:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Этот ID используется для идентификации Client‘а на Authorization Server‘е.

  • Client Secret:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Это пароль, который известен только Client‘у и Authorization Server‘у. Он позволяет им конфиденциально обмениваться информацией.

  • Authorization Code:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Временный код с небольшим периодом действия, который Client предоставляет Authorization Server‘у в обмен на Access Token.

  • Access Token:
    Иллюстрированное руководство по OAuth и OpenID Connect

    Ключ, который клиент будет использовать для связи с Resource Server‘ом. Этакий бейдж или ключ-карта, предоставляющий Client‘у разрешения на запрос данных или выполнение действий на Resource Server‘е от вашего имени.

Примечание: иногда Authorization Server и Resource Server являются одним и тем же сервером. Однако в некоторых случаях это могут быть разные серверы, даже не принадлежащие к одной организации. Например, Authorization Server может быть сторонним сервисом, которому доверяет Resource Server.

Теперь, когда мы ознакомились с основными понятиями OAuth 2.0, давайте вернемся к нашему примеру и подробно рассмотрим, что происходит в потоке OAuth.

Иллюстрированное руководство по OAuth и OpenID Connect

Проверяем работу ролей

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

Попробуйте зайти вначале под пользователем alice и нажать кнопку Get Superpowers!, затем зайдите под пользователем bob и проделайте то же самое.

Способы получения access token

Всего есть 4 способа:

Сценарии взаимодействия

У нас будет 3 проекта:

  1. IdentityServer — наш сервер аутентификации OpenId Connect.
  2. Api — наш тестовый веб-сервис.
  3. Client — наше клиентское приложение на JavaScript, основано на коде JavaScriptClient.

Сценарий взаимодействия таков: клиентское приложение Client авторизуется при помощи сервера аутентификации IdentityServer и получает access_token (JWT), который затем использует в качестве Bearer-токена для вызова веб-сервиса на сервере Api.

Стандарт OpenId Connect описывает разные варианты порядка прохождения аутентификации. Эти варианты на языке стандарта называются Flow.Implicit Flow, который мы рассматриваем в этой статье, включает такие шаги:

  1. Клиент готовит запрос на аутентификацию, содержащий нужные параметры запроса.
  2. Клиент шлёт запрос на аутентификацию на сервер авторизации.
  3. Сервер авторизации аутентифицирует конечного пользователя.
  4. Сервер авторизации получает подтверждение от конечного пользователя.
  5. Сервер авторизации посылает конечного пользователя обратно на клиент с id_token’ом и, если требуется, access_token’ом.
  6. Клиент валидирует id_token и получает Subject Identifierконечного пользователя.

Типы токенов

Зарегистрированным в IdentityServer4 клиентам позволено запрашивать у IdentityServer4identity-токен, access-токен и refresh-токен.

Введем еще два понятия:

Authenticatation Server Url — конечная точка для получения ключа доступа. Все запросы на предоставление и возобновление ключей доступа будем направлять на этот URL-адрес.

Resource Url — URL-адрес защищенного ресурса, по которому нужно обращаться, чтобы получить доступ к нему, передавая ему ключ доступа в заголовке авторизации.

Итог по openid


Имеем быструю аутентификацию по OpenID, из которых только livejournal не дает там email.

Заключение

Если Вы следовали инструкциям, на данный момент Вы:

  1. Своими руками сделали рабочую реализацию OpenId Connect Implicit Flow при помощи IdentityServer и oidc-client на платформе ASP.NET Core 1.1.
  2. Ознакомились с различными параметрами, позволяющими настроить части имплементации для Ваших нужд.
  3. И, главное, несколько подразобрались, как имплементация соотносится со стандартом, причём до того, как выучили стандарт наизусть.
Похожее:  Авторизация на сайте через ВК с занесением пользователя в базу данных (PHP) »

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *