查看源代码 Phoenix.Token (Phoenix v1.7.14)
在令牌中对数据进行签名/加密的便捷方法,用于通道、API 认证等。
存储在令牌中的数据已签名以防止篡改,并且可以选择加密。这意味着,只要密钥(见下文)保持机密,您就可以确信存储在令牌中的数据未被第三方篡改。但是,除非令牌已加密,否则使用此令牌存储私密信息(例如用户的敏感识别数据)并不安全,因为可以轻松对其进行解码。如果令牌已加密,其内容将对客户端保密,但最好还是尽可能少地编码秘密信息,以最大程度地减少密钥泄露的影响。
示例
在为 API 或通道生成唯一令牌时,建议使用用户的唯一标识符,通常是数据库中的 id。例如
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}
在该示例中,我们有用户的 id,我们生成一个令牌并使用给定 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
的两次调用中相同。例如,它可以称为“用户身份验证”,并在生成将在通道或 API 上用于身份验证用户的令牌时被视为命名空间。
第三个参数可以是您希望编码到令牌中的任何项(字符串、整数、列表等)。在成功验证后,将从令牌中提取相同的项。
用法
在对令牌进行签名后,我们可以通过多种方式将其发送给客户端。
一种是通过元标记
<%= tag :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、处理密码重置、电子邮件确认等。
摘要
类型
@type max_age_opt() :: {:max_age, pos_integer() | :infinity}
@type signed_at_opt() :: {:signed_at, pos_integer()}
函数
@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
在令牌中签名的最大年龄。
@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
- 设置令牌的时间戳(以秒为单位)。默认值为System.os_time(:millisecond)
:max_age
- 令牌的默认最大年龄。默认值为 86400 秒(1 天),并且可以在decrypt/4
上覆盖。
@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
- 设置令牌的时间戳(以秒为单位)。默认值为System.os_time(:millisecond)
:max_age
- 令牌的默认最大年龄。默认值为 86400 秒(1 天),并且可以在verify/4
上覆盖。
@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
在令牌中签名的最大年龄。