Green-sell.info

Новые технологии
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Bearer access token

Web API авторизация Bearer с поддержкой cookies

ru-RU | создано: 27.10.2016 | опубликовано: 27.10.2016 | обновлено: 02.01.2018 | просмотров за всё время: 13997

В статье описывается как для Web API использовать OAuth 2.0 аутентификацию и авторизацию на основе access_token (Bearer), и как этот токен хранить в cookie чтобы не приходилось при каждом новом открытии сайта вводить данные для получения этого токена.

Описание

Если вы захотите использовать OAuth 2.0 аутентификацию (и авторизацию) на основе access_token (например, Bearer), то вам придется в в заголовке каждого запроса передавать этот самый токен. Тут, как говорится, ничего нового, всё уже придумали за нас. Но если это так, то встает резонный вопрос: где его брать, чтобы его передавать? Об этом и о многом другом пойдет речь в этой статье.

Задача

Когда у меня созрела идея написания этой статьи, передо мной стояла задача запустить одностраничный сайт (Single Page Application) без использования ASP.NET MVC, но с возможностью использования Web API. Задача решена. Давайте ее разложим по пунктам. Итак, для решения задачи требуется решить следующие задачи:

  • получить токен (acces_token);
  • сохранить полученный токен в cookie;
  • при последующих посещениях сайта читать токен из cookie, чтобы аутентифицировать пользователя автоматически без ввода пароля и лонина.

Мелкие нюансы типа «поднять токен сервис» или «запросить у пользователя логин, если токен не обнаружен в cookie» опущены, хотя и обязательны.

Используемые инструменты и технологии

Я буду использовать Visual Studio 2015. При создания проекта я не использовал ASP.NET MVC 5, а создал пустой solution.

После этого я установил нужные nuget-пакеты, чтобы у меня получился проект с одной HTML-страницей (Single Page Application) и подключенным Web API. Для полноты картины приведу весь список установленных пакетов.

Обратите внимания, что у меня нет пакетов ASP.NET MVC в списке установленных.

Если вы скопировали файл packages.config из другого источника или создали его вручную без установки каждого из пакетов, то в Package Managment Console достаточно ввести следующую команду, чтоб все пакеты установились автоматически.

Далее подключим OWIN для сайта. Для этого создаем файл Startup.cs:

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

Так как этот файл, и в частности метод Configuration использует классы, которые буду показаны позже, проект не может быть собран и запущен. Поэтому не пытайтесь это сделать. Теперь, прокомментирую код по порядку следования строк, создавая недостающие классы и настройки.

Startup: Строки 6-7

Используется OWIN как основная спецификация взаимодействия между компонентами. ASP.NET MVC при этом не используется.

Startup: Строка 10

Стандартный для OWIN атрибут указывающий на то что при старте приложения класс c настройками для запуска является Startup.cs.

Startup: Строка 25

Создаем конфигурацию Web API и настраиваем основные параметры.

Важные строки выделены цветом. Здесь отключаем стандартную аутентификацию на сайте и регистрируем свой собственный AuthorizationBearerFilter, который выглядит следующим образом.

Комментарии по этому коду: в строке 11 проверяем наличие Authorization в Header; в строке 19 распаковываем (расшифровка) ticket и проделываем нужные нам манипуляции для проверки пользователя; в 27 строке устанавливаем IPrincipal для текущего запроса. Именно в 27 строке вы можете указать нужные параметры для пользователя: роли, права, настройки и т.д., которые, кстати, можно получить из БД или из другого сервиса.

Возвращаемся к Startup, следующая строка, требующая внимания, это строка номер 26, где происходит инициализация DependencyContainer. Я также приведу его полностью, закомментировав неважные строки:

Вы можете и вовсе не использовать DI-контейнер, или использовать другой на своё усмотрение. На самом деле, нам интересна выделенная 33 строка. В этой строке в DI-контейнере регистрируется, пожалуй самый главный класс, который отвечает за авторизацию и аутентификацию. Приведу его полностью, и как водится с комментариями после:

ApplicationOAuthProvider: Строка 13

Требуется создать свою реализацию OAuthAuthorizationServerProvider, поэтому наш класс унаследован от этого класса.

ApplicationOAuthProvider: Строка 19

Указываем тип аутентификации.

ApplicationOAuthProvider: Строка 24

Я использую врутренний ViewModel для проброса данных в сервис аутентификации в строке 29.

ApplicationOAuthProvider: Строка 31

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

ApplicationOAuthProvider: Строка 41

​Возращает зашифрованный AutenticationTicket, как результат успешной аутентификации.

Теперь снова вернемся к Startup классу.

Startup: Строка 36 и 42

В 36 как и 42 строке используется расширение AppBuilder.

В строке 14 по сути происходит запуск сайта. Так как я не использую ASP.NET MVC, то всё-таки хоть что-то должно как-то выводиться в браузер. Именно этот класс SinglePageWithWebApi и читает файл из папки Views и рендерит его в поток вызова без изменений HTML.

В строке 22 подключается класс BearerOnCookieAuthentication (middleware), ради которого и затевалась эта статья. Именно этот представленный ниже класс проделывает основную работу по обеспечению чтению Cookie и записи его наличия в свойство Authorization в коллекцию Header:

Теперь весь код собран воедино, следовательно можно откомпилировать проект. После успешного построения я запустил проект, и оказалось, что я случайно закомментировал лишную строку с регистрацией IAccountManager в DependencyContainer. Чтобы запуск состоялся, вам потребуется разкомментировать строчку с IAccountManager, а также вам потребуется файл index.html в папке Views.

Для удобства, тоже приведу полное содержание файла index.html:

Заключение

Авторизация настроена, хотя это и не видно. Единственное, что вам придется сделать самостоятельно, так это реализовать JavaScript функционал, который будет обращаться к ApiController, который вы тоже должны будете создать самостоятельно. ApiController теперь может быть помечен атрибутом Autorize. Авторизация и аутентификация будет осуществляться через access_token.

Ссылки

В заключении ссылка на вновь созданный проект, который выложен на GitHub.

Bearer access token

Реализация протокола OAuth2 в API

Для аутентификации и авторизации в API используется протокол OAuth2, из спецификации которого реализовано две стандартные схемы (flow): Client Credentials Grant и Authorization Code Grant, и одна нестандартная – Agency Client Credentials Grant.

Client Credentials Grant используется для работы с данными собственного аккаунта через API.

Agency Client Credentials Grant используется для работы с данными собственных клиентов агентств/менеджеров.

Authorization Code Grant используется для получения доступа к данным сторонних аккаунтов myTarget.

Первые две схемы доступны каждому API-клиенту, доступ к схеме Authorization Code Grant предоставляется только при выполнении условий.

Используя любой из данных методов, вы получите объект Access Token, содержащий ключи access_token и refresh_token. Ключом access_token должен быть подписан каждый запрос к API:

Client Credentials Grant

Agency Client Credentials Grant

Authorization Code Grant

Эта схема протокола OAuth2 позволяет получить токен стороннего пользователя myTarget. При создании доступа к схеме Authorization Code Grant должен указываться адрес «redirect_uri» — на него myTarget будет перенаправлять пользователей после предоставления (или отказа) ими доступа к своему аккаунту API-клиенту.

Читать еще:  Full join access

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

API-клиент перенаправляет пользователя на специальную страницу https://target.my.com/oauth2/authorize, указав параметры «response_type» (со значением «code»), «state» (сгенерированный на стороне клиента токен, используется для предотвращения CSRF — может содержать произвольный набор символов), свой «client_id» и список прав доступа «scope»:

Ответ содержит в том числе параметр user_id, в котором содержится идентификатор пользователя, предоставляющего доступ.

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

Scopes — права доступа

Права доступа определяют, какие действия может произвести API-клиент с данными предоставившего доступ аккаунта. Необходимые права указываются через запятую в параметре «scope» запроса доступа у пользователя в схеме Authorization Code Grant. В зависимости от типа пользователя запрашиваемые права доступа делятся на три группы.

Для обычного пользователя-рекламодателя:

  • read_ads — чтение статистики и РК;
  • read_payments — чтение денежных транзакций и баланса;
  • create_ads — создание и редактирование настроек РК, баннеров, аудиторий (ставки, статус, таргетинги и т.п.).

Для пользователей-агентств и пользователей-представительств:

  • create_clients — создание новых клиентов;
  • read_clients — просмотр клиентов и операции от их имени;
  • create_agency_payments — переводы средств на счёта клиентов и обратно.

Для пользователей-менеджеров:

  • read_manager_clients — просмотр клиентов и операции от их имени;
  • edit_manager_clients — изменение параметров клиентов;
  • read_payments — чтение денежных транзакций и баланса.

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

Работа с токенами

Лимит на количество токенов

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

Не вечные токены автоматически удаляются по истечении месяца неактивности (указано в поле «expires_in»).

По достижении лимита в ответ на попытку получить новый токен будет возвращена ошибка с HTTP-кодом 403.

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

Удаление токенов

Срок действия access-токена

Каждый полученный токен доступа по умолчанию является действительным в течение суток. На это указывает свойство «expires_in» в ответе на запрос токена доступа. Ограниченный срок жизни позволяет более надёжно защитить значение «access_token». Даже завладев значением одного «access_token», злоумышленник не сможет выполнить запросы с ним по истечении срока действия или после первого обновления токена.

Менее безопасный способ – «вечные» токены доступа. Для получения «access_token» без ограничения срока действия, необходимо добавить GET-параметр «permanent=true» в запрос создания или обновления токена. Например:

Обновление токена доступа

В объекте токена Access Token также указывается ключ «refresh_token» — специальный токен для обновления ключа access_token и продления времени жизни объекта. За это отвечает схема Refreshing an Access Token в протоколе OAuth2.

Запрос на обновление токена доступа:

Важно учитывать, что обновление токена не создаёт новый экземпляр: меняется значение «access_token», старое значение ключа перестаёт работать. Это может привести к проблемам при работе с API в несколько потоков: два потока могут одновременно обнаружить, что токен истёк и отправить запрос на обновление. Запрос, пришедший первым, обновит токен и начнёт его использовать, в то время как второй поток обновит токен ещё раз, и первый поток будет пытаться использовать уже несуществующий токен.

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

Другим вариантом решения этой проблемы может быть включение опции обновления «refresh_token» при каждом обновлении «access_token». Тогда первый поток обновит и «access_token», и «refresh_token», а во втором нужно обработать ошибку о неизвестном «refresh_token» и перечитать «access_token» из хранилища. Но при обновления «refresh_token» нужно обязательно хранить его самое последнее значение, иначе вы больше не сможете обновить «access_token», и придётся выписывать новый. Эту опцию OAuth-клиента сейчас можно включить только по запросу в службу поддержки.

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

Getting Access Tokens

In this topic, you will learn how to get access tokens and show you strategies for implementing this logic in your apps.

Getting a token

If you just want to generate an access token for testing an API request, you can use this sample app.

Tokens are obtained from the Brightcove OAuth API. Before you can get access tokens, you first need to obtain client credentials (a client id and a client secret) that are specific to the API and operations that you want access to. To get your client credentials, see Managing API Credentials.

Once you have your credentials, you obtain an access token by making a POST request to:

You must pass the following headers with this call:

  • Content-Type: application/x-www-form-urlencoded
  • Authorization: Basic :

The entire : string must be Base64-encoded (curl will automatically Base64-encode the string if you pass it as —user credentials; in other languages, you’ll need to handle the Base64-encoding yourself).

You must also send the following key/value pair as the request body or as URL parameter:

The response will look like this (pretty-printed here for readability):

The access_token value is what you must pass in an Authorization header with your API call in this form:

The expires_in value is the number of seconds that the access token is valid for.

Implementation Strategies

If your app will only be making sporadic calls to the Brightcove APIs, you might as well ignore the expires_in parameter and just fetch a new access token for every call. In that case, the processing sequence will look like this:

Get New Token

On the other hand, if you know that your app will frequently make many API calls in quick succession (for, say, generating long reports), then it will be more efficient to fetch access tokens only when you need them. There are two basic ways of doing this:

  1. Go ahead and try the API call and if you get an UNAUTHORIZED error in response, go fetch a new token and make the API call again. In this case, the processing sequence will look like this: Get Token with Check for Call Fail
  2. Another approach would be to add the expires_in value to the current time in Epoch seconds each time you fetch a token, and then on later API calls, check the expires time against the current time to see if you need to fetch a new token. In this case, your processing sequence will look like this: Get Token with Check for Expiration

Postman and Insomnia

Several useful testing tools for REST APIs can be set up to work with the Brightcove OAuth system to get access tokens. We have guides that include steps for doing this for two of most popular cross-platform tools:

Code Samples

Here are some code samples to help you get started.

Shell script example

The first example is a shell script that implements the first implementation logic above: it takes inputs from the user, always gets a new token, and then makes the API call. The script will work on any of the Brightcove APIs, and you may find it useful for testing API calls as you build your app.

Note: this script uses cURL, and also the jq command line app. See Set up cURL and jq for setup instructions. The Python json.tool is also used to pretty-print the response, but that should already be installed on your system.

To run the script, save the code as api-tester.sh on your system, open a command line in the same folder, and enter bash api-tester.sh — you will be prompted for the following inputs:

  • client id (required)
  • client secret (required)
  • the full API call (required)
  • the HTTP verb for the call: GET | POST | PATCH | PUT | DELETE (required)
  • data for the request body (optional)

Shell script code

Ruby example

The next example is a Ruby script that also employs the first implementation logic: always get a token and then make the API call. This example makes a call to the Analytics API, but can be adapted to work with any of the APIs.

Ruby code

Python example

This sample is a Python script that implements the 3rd implementation logic above. It attempts to make an Analytics API call, but if the call fails on an UNAUTHORIZED error, it fetches a new access token and retries the call.

This script also reads the client credentials from an external file — the credentials data file is shown below the Python code.

Python code

Credentials file for Python sample

PHP example

This is a simple proxy that takes client credentials and an API call, gets an access token, makes the API request, and returns the results to the client.

Authentication API

This page will describe the steps required for your application to authorize against and integrate with Home Assistant instances. See a demo powered by our helper lib home-assistant-js-websocket.

Each user has their own instance of Home Assistant which gives each user control over their own data. However, we also wanted to make it easy for third party developers to create applications that allow users to integrate with Home Assistant. To achieve this, we have adopted the OAuth 2 specification combined with the OAuth 2 IndieAuth extension for generating clients.

#Clients

Before you can ask the user to authorize their instance with your application, you will need a client. In traditional OAuth2, the server needs to generate a client before a user can authorize. However, as each server belongs to a user, we’ve adopted a slightly different approach from IndieAuth.

The client ID you need to use is the website of your application. The redirect url has to be of the same host and port as the client ID. For example:

  • client id: https://www.my-application.io
  • redirect uri: https://www.my-application.io/hass/auth_callback

If you require a different redirect url (ie, if building a native app), you can add an HTML tag to the content of the website of your application (the client ID) with an approved redirect url. For example, add this to your site to whitelist redirect uri hass://auth :

Home Assistant will scan the first 10kB of a website for link tags.

#Authorize

All example URLs here are shown with extra spaces and new lines for display purposes only.

The authorize url should contain client_id and redirect_uri as query parameters.

Optionally you can also include a state parameter, this will be added to the redirect uri. The state is perfect to store the instance url that you are authenticating with. Example:

The user will navigate to this link and be presented with instructions to log in and authorize your application. Once authorized, the user will be redirected back to the passed in redirect uri with the authorization code and state as part of the query parameters. Example:

This authorization code can be exchanged for tokens by sending it to the token endpoint (see next section).

#Token

The token endpoint returns tokens given valid grants. This grant is either an authorization code retrieved from the authorize endpoint or a refresh token. In thee case of refresh token, the token endpoint is also capable of revoking a token.

All interactions with this endpoint need to be HTTP POST requests to http://your-instance.com/auth/token with the request body encoded in application/x-www-form-urlencoded .

#Authorization code

All requests to the token endpoint need to contain the exact same client ID as was used to redirect the user to the authorize endpoint.

Use the grant type authorization_code to retrieve the tokens after a user has successfully finished the authorize step. The request body is:

The return response will be an access and refresh token:

The access token is a short lived token that can be used to access the API. The refresh token can be used to fetch new access tokens. The expires_in value is seconds that the access token is valid.

An HTTP status code of 400 will be returned if an invalid request has been issued. The HTTP status code will be 403 if a token is requested for an inactive user.

#Refresh token

Once you have retrieved a refresh token via the grant type authorization_code , you can use it to fetch new access tokens. The request body is:

The return response will be an access token:

An HTTP status code of 400 will be returned if an invalid request has been issued.

#Revoking a refresh token

client_id is not need for revoke refresh token

The token endpoint is also capable of revoking a refresh token. Revoking a refresh token will immediately revoke the refresh token and all access tokens that it has ever granted. To revoke a refresh token, make the following request:

The request will always respond with an empty body and HTTP status 200, regardless if the request was successful.

#Long-lived access token

A long-lived access token is usually used for 3rd party API calls and webhook-ish integrations. To generate a long-lived access token, an active websocket connection has to be established.

Send websocket command auth/long_lived_access_token will create a long-lived access token for current user. Access token will not be saved in Home Assistant. User need to record the token in secure place.

Result will be a long-lived access token:

Additionally, a long-lived access token can be created using the UI tool located at the bottom of the user’s Home Assistant profile page.

#Making authenticated requests

Once you have an access token, you can make authenticated requests to the Home Assistant APIs.

For the websocket connection, pass the access token in the authentication message.

For HTTP requests, pass the token type and access token as the authorization header:

#Example: cURL

#Example: Python

#Example: NodeJS

If the access token is no longer valid, you will get a response with HTTP status code 401 unauthorized. This means that you will need to refresh the token. If the refresh token doesn’t work, the tokens are no longer valid and so the user is no longer logged in. You should clear the user’s data and ask the user to authorize again.

#Signed paths

Sometimes you want a user to make a GET request to Home Assistant to download data. In this case the normal auth system won’t do, as we can’t link the user to an API with the auth header attached to it. In that case, a signed path can help.

A signed path is a normal path on our server, like /api/states , but with an attached secure authentication signature. The user is able to navigate to this path and will be authorised as the access token that created the signed path. Signed paths can be created via the websocket connection and are meant to be shortlived. The default expiration is 30 seconds.

To get a signed path, send the following command:

The response will contain the signed path:

Some things to note about a signed path:

  • If the refresh token is deleted, the signed url is no longer valid.
  • If the user is deleted, the signed url is no longer valid (because the refresh token will be deleted).
  • If Home Assistant is restarted, the signed url is no longer valid.
  • Access is only validated when the request is received. If a response takes longer than the expiration time (ie, downloading a large file), the download will continue after the expiration date has passed.

WordPress.org

Русский

API Bearer Auth

Описание

The API Bearer Auth plugin enables authentication for the REST API by using JWT access an refresh tokens. After the user logs in, the access and refresh tokens are returned and can be used for the next requests. Issued tokens can be revoked from within the users admin screen. See below for the endpoints.

Note that after activating this plugin, all REST API endpoints will need to be authenticated, unless the endpoint is whitelisted in the api_bearer_auth_unauthenticated_urls filter (see FAQ for how to use this filter).

Access tokens can be formatted as JWT tokens. For this to work, you first have to create a secret and add it to the wp-config.php file. If you don’t do this, access tokens will work also, but are just random strings. To create a random secret key, you can do for example:

And then add the result to wp-config:

If you have problems, you can verify your JWT tokens at: https://jwt.io/

Revoke tokens

This plugin adds a column to the users table in de admin where you can see when a token expires. You can also revoke tokens by selection the «Revoke API tokens» from the bulk actions select box.

API endpoints

Note that all endpoints expect JSON in the POST body.

Login

Make sure to save the access and refresh token!

Refresh access token

Response when sending a wrong refresh token is a 401:

Do a request

After you have the access token, you can make requests to authenticated endpoints with an Authorization header like this:

Note that Apache sometimes strips out the Authorization header. If this is the case, make sure to add this to the .htaccess file:

If you are not logged in or you send an invalid access token, you get a 401 response:

Установка

  1. Upload the plugin files to the /wp-content/plugins/api-bearer-auth directory, or install the plugin through the WordPress plugins screen directly.
  2. If you want your access tokens to be formatted as JWT tokens, define a random string as a API_BEARER_JWT_SECRET define in your wp-config.php file.
  3. Activate the plugin through the ‘Plugins’ screen in WordPress.
  4. From now on, every REST API endpoint needs to be authenticated.

Часто задаваемые вопросы

By default an access token is valid for 1 day. You can change this, by defining the API_BEARER_ACCESS_TOKEN_VALID_IN_SECONDS constant in your wp-config.php file.

Whitelist unauthenticated URLs

By default all REST API endpoints are only available for authenticated users. If you want to add some more endpoints to this whitelist, you can use the api_bearer_auth_unauthenticated_urls filter. Note that you need to specify the endpoint relative to the site_url() and that you can specify regular expressions.

Ссылка на основную публикацию
Adblock
detector