Phoenix.Token
Исходный кодУдобные средства для подписывания и шифрования данных в токенах, используемых в каналах, для аутентификации API и других задач.
Данные, хранящиеся в токене, подписываются для защиты от подмены и, при необходимости, шифруются. Это означает, что, пока ключ (см. ниже) остается секретным, вы можете быть уверены, что хранящиеся в токене данные не были изменены третьей стороной. Однако, если токен не зашифрован, его небезопасно использовать для хранения конфиденциальной информации, например чувствительных идентификационных данных пользователя, так как его можно легко декодировать. Если токен зашифрован, его содержимое будет скрыто от клиента, но рекомендуется хранить в нем как можно меньше секретной информации, чтобы свести к минимуму последствия утечки ключа.
Пример
При создании уникального токена для использования в API или канале рекомендуется использовать уникальный идентификатор пользователя, обычно его идентификатор в базе данных. Например:
iex> user_id = 1
iex> token = Phoenix.Token.sign(MyAppWeb.Endpoint, "user auth", user_id)
iex> Phoenix.Token.verify(MyAppWeb.Endpoint, "user auth", token, max_age: 86400)
{:ok, 1}
В этом примере у нас есть идентификатор пользователя, мы создаем токен и проверяем его с помощью базового секретного ключа, настроенного в указанном endpoint. Мы гарантируем, что токен будет действителен только один день, задав максимальный срок действия (это рекомендуется).
Первым аргументом для sign/4, verify/4, encrypt/4 и decrypt/4 может быть одно из следующего:
- имя модуля конечной точки Phoenix (как показано выше) — базовый секретный ключ извлекается из конечной точки
-
Plug.Conn— базовый секретный ключ извлекается из конечной точки, хранящейся в соединении -
Phoenix.SocketилиPhoenix.LiveView.Socket— базовый секретный ключ извлекается из конечной точки, хранящейся в сокете - строка, представляющая сам базовый секретный ключ. Для обеспечения достаточной энтропии следует использовать базовый ключ, содержащий не менее 20 случайно сгенерированных символов
Второй аргумент — это криптографическая соль, которая должна быть одинаковой в обоих вызовах sign/4 и verify/4 либо в обоих вызовах encrypt/4 и decrypt/4. Например, ее можно назвать «user auth» и использовать как пространство имен при создании токена для аутентификации пользователей в каналах или API.
Третий аргумент может быть любым термом (строкой, целым числом, списком и т. д.), который вы хотите закодировать в токене. При успешной проверке этот же терм будет извлечен из токена.
Использование
После подписания токена мы можем передать его клиенту несколькими способами.
Один из способов — через метатег:
<meta name="channel_token" content={Phoenix.Token.sign(@conn, "user auth", @current_user.id)}>
Или через конечную точку, которая возвращает токен:
def create(conn, params) do
user = User.create(params)
render(conn, "user.json",
%{token: Phoenix.Token.sign(conn, "user auth", user.id), user: user})
end
Получив токен, клиент может отправить его обратно серверу для аутентификации. Например, с его помощью можно аутентифицировать пользователя в канале Phoenix:
defmodule MyApp.UserSocket do
use Phoenix.Socket
def connect(%{"token" => token}, socket, _connect_info) do
case Phoenix.Token.verify(socket, "user auth", token, max_age: 86400) do
{:ok, user_id} ->
socket = assign(socket, :user, Repo.get!(User, user_id))
{:ok, socket}
{:error, _} ->
:error
end
end
def connect(_params, _socket, _connect_info), do: :error
end
В этом примере клиент phoenix.js отправит токен в команде connect, после чего сервер проверит его.
Phoenix.Token также можно использовать для проверки API, обработки сброса паролей, подтверждения адреса электронной почты и других задач.
Краткое описание
Типы
- decrypt(context, secret, token, opts \\ [])
Расшифровывает исходные данные из токена и проверяет их целостность.
- encrypt(context, secret, data, opts \\ [])
Кодирует, шифрует и подписывает данные в токен, который можно отправить клиентам. Использование этой функции совпадает с использованием
sign/4, но данные извлекаются с помощьюdecrypt/4, а неverify/4.- sign(context, salt, data, opts \\ [])
Кодирует и подписывает данные в токен, который можно отправить клиентам.
- verify(context, salt, token, opts \\ [])
Декодирует исходные данные из токена и проверяет их целостность.
Функции
Типы
context()Исходный код
@type context() ::
Plug.Conn.t()
| %{:endpoint => atom(), optional(atom()) => any()}
| atom()
| binary() max_age_opt()Исходный код
@type max_age_opt() :: {:max_age, pos_integer() | :infinity} shared_opt()Исходный код
@type shared_opt() ::
{:key_iterations, pos_integer()}
| {:key_length, pos_integer()}
| {:key_digest, :sha256 | :sha384 | :sha512} signed_at_opt()Исходный код
@type signed_at_opt() :: {:signed_at, pos_integer()} Функции
decrypt(context, secret, token, opts \\ [])Исходный код
@spec decrypt(context(), binary(), binary(), [shared_opt() | max_age_opt()]) :: term()
Расшифровывает исходные данные из токена и проверяет их целостность.
Использование этой функции совпадает с использованием verify/4, но применяется к зашифрованным токенам.
Параметры
-
:key_iterations— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 1000 -
:key_length— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 32 -
:key_digest— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию —:sha256 -
:max_age— проверяет токен, только если с момента его создания прошло не более указанного максимального срока действия в секундах. По умолчанию используется максимальный срок действия, подписанный в токене функциейencrypt/4.
encrypt(context, secret, data, opts \\ [])Исходный код
@spec encrypt(context(), binary(), term(), [ shared_opt() | max_age_opt() | signed_at_opt() ]) :: binary()
Кодирует, шифрует и подписывает данные в токен, который можно отправить клиентам. Использование этой функции совпадает с использованием sign/4, но данные извлекаются с помощью decrypt/4, а не verify/4.
Параметры
-
:key_iterations— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 1000 -
:key_length— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 32 -
:key_digest— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию —:sha256 -
:signed_at— задает временную метку токена в секундах. Если значение не указано, используется текущее время в миллисекундах. -
:max_age— максимальный срок действия токена по умолчанию в секундах. По умолчанию — 86400 секунд (1 день); его можно переопределить при вызовеdecrypt/4.
sign(context, salt, data, opts \\ [])Исходный код
@spec sign(context(), binary(), term(), [ shared_opt() | max_age_opt() | signed_at_opt() ]) :: binary()
Кодирует и подписывает данные в токен, который можно отправить клиентам.
Параметры
-
:key_iterations— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 1000 -
:key_length— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 32 -
:key_digest— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию —:sha256 -
:signed_at— задает временную метку токена в секундах. Если значение не указано, используется текущее время в миллисекундах. -
:max_age— максимальный срок действия токена по умолчанию в секундах. По умолчанию — 86400 секунд (1 день); его можно переопределить при вызовеverify/4.
verify(context, salt, token, opts \\ [])Исходный код
@spec verify(context(), binary(), binary(), [shared_opt() | max_age_opt()]) ::
{:ok, term()} | {:error, :expired | :invalid | :missing} Декодирует исходные данные из токена и проверяет их целостность.
Примеры
В этом сценарии мы создадим токен, подпишем его, а затем передадим клиентскому приложению. Клиент будет использовать этот токен для аутентификации запросов к ресурсам сервера. Дополнительные сведения о создании токенов см. в кратком описании Phoenix.Token.
iex> user_id = 99 iex> secret = "kjoy3o1zeidquwy1398juxzldjlksahdk3" iex> namespace = "user auth" iex> token = Phoenix.Token.sign(secret, namespace, user_id)
Обычно токен передается клиенту с помощью cookie, тела JSON-ответа или HTTP-заголовка. Пока предположим, что клиент получил токен, который может использовать для проверки запросов к защищенным ресурсам.
Получив запрос, сервер может использовать verify/4, чтобы определить, следует ли предоставить клиенту запрошенные ресурсы:
iex> Phoenix.Token.verify(secret, namespace, token, max_age: 86400)
{:ok, 99}
В этом примере мы знаем, что клиент отправил действительный токен, поскольку verify/4 вернула кортеж типа {:ok, user_id}. Теперь сервер может обработать запрос.
Однако, если бы клиент отправил просроченный или недействительный токен либо nil, функция verify/4 вернула бы ошибку:
iex> Phoenix.Token.verify(secret, namespace, expired, max_age: 86400)
{:error, :expired}
iex> Phoenix.Token.verify(secret, namespace, invalid, max_age: 86400)
{:error, :invalid}
iex> Phoenix.Token.verify(secret, namespace, nil, max_age: 86400)
{:error, :missing}
Параметры
-
:key_iterations— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 1000 -
:key_length— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию — 32 -
:key_digest— параметр, передаваемый вPlug.Crypto.KeyGeneratorпри создании ключей шифрования и подписи. По умолчанию —:sha256 -
:max_age— проверяет токен, только если с момента его создания прошло не более указанного максимального срока действия в секундах. По умолчанию используется максимальный срок действия, подписанный в токене функциейsign/4.
© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix.hexdocs.pm/Phoenix.Token.html