如何使用 Elixir 生成随机 url 安全字符串

How to generate a random url safe string with Elixir

我需要能够生成随机 url 安全字符串,这样我就可以在 link 中使用它们(比如在发送到用户电子邮件的激活 link 中),所以我怎样才能生成它?有没有办法只使用 Elixir 来做到这一点,或者我必须使用一些库?

您可以改为生成一个 Base64 编码的字符串以用作确认令牌。然后,此确认令牌将保存到您的数据库中,并作为参数传递给激活 link。您的激活 url 看起来像:

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

希望对您有所帮助!

您可以轻松地定义一个模块来执行此操作。在此示例中,@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"

如@JimGray 的评论所述,您的规范实际上应该根据您希望由随机 URL 安全字符串表示的熵量来确定。类似于 "I need N bits" 因为有人告诉你使用 N 位,或者 "I want to avoid repeat in N strings and I can accept a risk of 1 in n of a collision"。无论哪种方式,它直接与熵有关,只是间接与字符串长度有关。

例如,请确保如果您使用@Gjaldon 的回答这样的解决方案,即使使用了 512 位随机性,您也能理解,random_string(64) 生成的实际字符串的熵量是 320 位.这是否足够当然取决于您的场景,如上所述,这可能最好表示为,例如,"I need a million strings with no more than a 1 in a trillion risk of repeat",在这种情况下,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"

无论哪种方式,控制和理解都是很好的事情。