【发布时间】:2015-11-07 05:03:18
【问题描述】:
我需要能够生成随机 url 安全字符串,以便可以在链接中使用这些字符串(例如在发送到用户电子邮件的激活链接中),那么我该如何生成呢?有没有办法只使用 Elixir 或者我必须使用一些库?
【问题讨论】:
我需要能够生成随机 url 安全字符串,以便可以在链接中使用这些字符串(例如在发送到用户电子邮件的激活链接中),那么我该如何生成呢?有没有办法只使用 Elixir 或者我必须使用一些库?
【问题讨论】:
您可以做的是生成一个 Base64 编码的字符串以用作确认令牌。然后,此确认令牌将保存到您的数据库并作为参数传递给激活链接。您的激活网址如下所示:
activation_url(MyApp.Endpoint, :confirm, confirm_id: confirm_id)
上面的 url 助手假设你在那个控制器中有一个 MyApp.ActivationController 和一个 confirm/2 动作。要生成confirm_id,您可以这样做:
def random_string(length) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
end
# random_string(64)
在您的MyApp.ActivationController.confirm/2 中,您可以使用以下代码:
def confirm(conn, %{"confirm_id" => confirm_id}) do
user = Repo.get_by(User, confirm_id: confirm_id)
User.confirm(user)
conn
|> put_flash(:info, "Account confirmed!")
|> redirect(to: "/")
end
希望有帮助!
【讨论】:
random_string/1 的结果会是 url 安全的吗?
您可以轻松地定义一个模块来执行此操作。在此示例中,@chars 确定生成的字符串中出现的字符。
defmodule StringGenerator do
@chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |> String.split("")
def string_of_length(length) do
Enum.reduce((1..length), [], fn (_i, acc) ->
[Enum.random(@chars) | acc]
end) |> Enum.join("")
end
end
StringGenerator.string_of_length(3) # => "YCZ"
【讨论】:
@chars 还包含空字符串,这意味着生成的字符串可能比length 短。要仅获取一个字符的字符串,请使用String.split("", trim: true)。
String.codepoints 而不是String.split。使用map,fwiw:1..length |> Enum.map(fn _i -> Enum.random(@chars) end) |> Enum.join("") 也可能更清洁。
正如@JimGray 的评论中所指出的,您的规范实际上应该是您希望由随机 URL 安全字符串表示的熵量。类似于“我需要 N 位”的内容,因为有人告诉您使用 N 位,或者“我想避免在 N 个字符串中重复,并且我可以接受 1 in n 的碰撞风险”。无论哪种方式,它都直接与熵有关,而仅间接与字符串长度有关。
例如,请确保如果您使用像 @Gjaldon 的答案这样的解决方案,即使使用了 512 位随机性,您也能理解,random_string(64) 生成的实际字符串的熵量是 320 位。这是否足够当然取决于您的情况,如上所述,这可能最好表示为,例如,“我需要一百万个字符串,重复风险不超过万亿分之一”,在这种情况下,320 位是严重的过度杀伤,因为你只需要 79。
如果您想对生成随机字符串有更多的控制和理解,请查看EntropyString。使用该库,您可以执行以下操作来获取具有 256 位熵的字符串:
iex> defmodule Id, do: use EntropyString, charset: charset64
iex> Id.token
"ziKYK7t5LzVYn5XiJ_jYh30KxCCsLorRXqLwwEnZYHJ"
或者,如果您意识到重复风险为万亿分之一的一百万个字符串是 足够了,您可以像这样设置您的 Id 生成:
iex> defmodule Id do
...> use EntropyString, charset: charset64
...> @bits entropy_bits(1.0e6, 1.0e12)
...> def random, do: Id.random_string(@bits)
...> end
iex> Id.random
"FhlGVXOaXV9f3f"
不管怎样,控制和理解都是不错的选择。
【讨论】: