【问题标题】:How to generate a random url safe string with Elixir如何使用 Elixir 生成随机 url 安全字符串
【发布时间】:2015-11-07 05:03:18
【问题描述】:

我需要能够生成随机 url 安全字符串,以便可以在链接中使用这些字符串(例如在发送到用户电子邮件的激活链接中),那么我该如何生成呢?有没有办法只使用 Elixir 或者我必须使用一些库?

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

    您可以做的是生成一个 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 安全的吗?
    • 我更新了答案以使用 url-safe Base64 版本。
    • 旁注:您通常需要目标随机位数而不是字符串长度,例如会话令牌应至少为 256 位(32 字节)。为此,应省略 binary_part() 调用,此时长度将是生成的密钥的熵(以字节为单位)。
    【解决方案2】:

    您可以轻松地定义一个模块来执行此操作。在此示例中,@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("") 也可能更清洁。
    【解决方案3】:

    正如@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"
    

    不管怎样,控制和理解都是不错的选择。

    【讨论】:

      猜你喜欢
      • 2012-02-12
      • 2017-01-15
      • 1970-01-01
      • 2015-12-30
      • 1970-01-01
      • 1970-01-01
      • 2018-11-26
      • 2018-09-03
      • 1970-01-01
      相关资源
      最近更新 更多