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

时间:2015-08-14 02:59:17

标签: elixir phoenix-framework

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

3 个答案:

答案 0 :(得分:48)

您可以做的是生成一个Base64编码的字符串,用作确认令牌。然后,此确认令牌将保存到您的数据库,并作为参数传递给激活链接。您的激活网址如下所示:

activation_url(MyApp.Endpoint, :confirm, confirm_id: confirm_id)

上面的网址助手假定您在该控制器中有MyApp.ActivationControllerconfirm/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

希望有所帮助!

答案 1 :(得分:10)

You can easily define a module to do this. In this example, @chars determines what characters appear in your generated strings.

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"

答案 2 :(得分:3)

正如@ JimGray评论中所述,您的规范应该是您想要通过随机URL安全字符串表示的熵数量。类似于"我需要N位"因为有人告诉你要使用N位,或者#34;我想避免在N个字符串中重复,我可以接受n中碰撞的风险1"。无论哪种方式,它都直接关于熵,并且只是间接地关于字符串长度。

例如,如果您使用@ Gjaldon'等解决方案,请务必使用即使使用了512位随机性,你也能理解,random_string(64)生成的实际字符串的熵数是320位。这是否足够当然取决于您的情况,如上所述,可能最好表达为,例如,"我需要一百万个字符串,一万亿次重复风险不超过1# 34;,在这种情况下,320位是严重的过度杀伤,因为你只需要79。

如果您想要更多地控制和理解生成随机字符串,请查看EntropyString。使用该库,您可以执行以下操作以获取具有256位熵的字符串:

iex> defmodule Id, do: use EntropyString, charset: charset64
iex> Id.token
"ziKYK7t5LzVYn5XiJ_jYh30KxCCsLorRXqLwwEnZYHJ"

或者如果你意识到百万字符串的重复风险为1万亿分之一 足够的,您可以像以下一样设置您的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"

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