Поддержка анонимных jwt токенов в IdentityServer4 при помощи AnonymousIdentity

от автора


Недавно мне потребовалось реализовать поддержку анонимной аутентификации пользователей на основе OpenId Connect и OAuth 2.0 на платформе ASP.NET Core. Здесь не будет объясняться спецификация данных протоколов, для этого есть полно статей на хабре. Перейдем к сути.

Зачем нужен анонимный токен? Для авторизации анонимного пользователя на API ресурсе, особенно в архитектуре микросервисов, к тому же, он может изменить состояние нашего приложения, например, Васе понравилась футболка с котиками, он добавляет ее в корзину интернет-магазина и, возможно, оформляет заказ в качестве гостя. Чтобы понять, что это был именно Василий, анонимный токен содержит идентификатор анонимного пользователя и идентификатор сессии. Когда Василий войдет в систему, эти параметры будут включены в аутентифицированный токен.

К тому же, анонимный токен доступа может содержать любые дополнительные утверждения(или claims).

Инструменты

  • IdentityServer4 для поддержки OpenId Connect и OAuth 2.0
  • AnonymousIdentity для поддержки анонимных токенов в IdentityServer4

Имплементация

IdentityServer4 имеет множество примеров на GitHub.

Добавить поддержку анонимных токенов достаточно просто:

  • Установить AnonymousIdentity в проект с IdneitityServer4
    Install-Package AnonymousIdentity 
  • Зарегистрировать AnonymousIdentity в Startup.cs
    services.AddIdentityServer() // остальные регистрации .AddAnonymousAuthentication();

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

Рассмотрим получение анонимного токена для Implicit Flow и Authorization Code Flow.

Запрос к точке авторизации

Чтобы следовать спецификации, запрос к точке авторизации для Implicit Flow выглядит следующим образом.

GET /connect/authorize?     client_id=client1&     scope=openid email api1&     response_type=id_token token&     redirect_uri=https://myapp/callback&     state=abc&     nonce=xyz&     acr_values=0&     response_mode=json

Для Authorization Code Flow аналогичный запрос с response_type = code (PKCE опционально).

Различия между обычным и анонимным запросом в двух параметрах:

  • Параметр acr_values = 0 сигнализирует об анонимном входе в систему. Если интересно, можно почитать спецификацию OpenId Connect.
  • Параметр response_mode = json служит для ответа в виде Json без лишних перенаправлений.

Получение токена

В зависимости от состояния аутентификации, возвращается либо анонимный, либо аутентифицированный токен.

Implicit Flow

В данном случае, точка авторизации отвечает в виде Json, включая токен доступа.

{   "id_token": <id_token>,   "access_token": <access_token>,   "token_type": "Bearer",   "expires_in": "2592000",   "scope": "openid email api1",   "state": "abc",   "session_state": <optional> }

Authorization Code Flow

При таком подходе, точка авторизации отвечает в виде Json, включая код авторизации.

{   "code": <authorization_code>,   "scope": "openid email api1",   "state": "abc",   "session_state": <optional> }

Затем, необходимо обменять код на токен стандартным методом.

Формируем запрос к конечной точке токена.

POST /connect/token     client_id=client2&     client_secret=secret&     grant_type=authorization_code&     code=`&     redirect_uri=https://myapp/callback

В результате, конечная точка токена отвечает в виде Json, включая токен доступа.

{   "id_token": <id_token>,   "access_token": <access_token>,   "token_type": "Bearer",   "expires_in": "2592000",   "scope": "openid email api1" }

Сравнение анонимного и аутентифицированного токена

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

{   "nbf": 1566849147,   "exp": 1569441147,   "iss": "https://server",   "aud": [     "https://server/resources",     "api"   ],   "client_id": "client1",   "sub": "abda9006-5991-4c90-a88c-c96764027347",   "auth_time": 1566849147,   "idp": "local",   "ssid": "9e6453dbaf5ffdb03f08812f759d3cdf",   "scope": [     "openid",     "email",     "api1"   ],   "amr": [     "anon"   ] }

Определить, что пользователь является анонимным можно по методу аутентификации(amr).
Идентификатор "общей" сессии(ssid) и идентификатор субъекта(sub) будут включены в аутентифицированный токен, при последующем входе пользователя в систему.

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

{   "nbf": 1566850295,   "exp": 1566853895,   "iss": "https://server",   "aud": [     "https://server/resources",     "api"   ],   "client_id": "client1",   "sub": "bob",   "auth_time": 1566850295,   "idp": "local",   "aid": "abda9006-5991-4c90-a88c-c96764027347",   "ssid": "9e6453dbaf5ffdb03f08812f759d3cdf",   "scope": [     "openid",     "email",     "api1"   ],   "amr": [     "pwd"   ] }

Как вы можете заметить, идентификатор анонимного пользователя(aid) совпадает с sub анонимного токена, так же как и ssid. Если клиент не инициировал анонимный вход, то аутентифицированный токен будет содержать только ssid.

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

Заключение

В данной статье мы рассмотрели сценарий получения анонимного/аутентифицированного токена с помощью IdentityServer4 c расширением AnonymousIdentity.

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


ссылка на оригинал статьи https://habr.com/ru/post/466467/


Комментарии

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

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