web-dev-qa-db-ja.com

ElixirでランダムなURLセーフストリングを生成する方法

リンク(ユーザーのメールに送信されたアクティベーションリンクなど)で使用できるように、ランダムなURLセーフ文字列を生成できるようにする必要があります。どのように生成できますか? Elixirでのみそれを行う方法はありますか、またはいくつかのライブラリを使用する必要がありますか?

35
NoDisplayName

代わりにできることは、確認トークンとして使用されるBase64エンコード文字列を生成することです。この確認トークンはDBに保存され、アクティベーションリンクにパラメーターとして渡されます。アクティベーション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で、コードlikを使用できます。

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

お役に立てば幸いです!

50
Gjaldon

これを行うモジュールを簡単に定義できます。この例では、@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"
10
Nathan Long

@JimGrayのコメントで述べたように、仕様は実際には、ランダムなURLセーフストリングで表現したいエントロピーの量に基づいている必要があります。誰かがNビットを使うようにあなたに言ったので、「私はNビットが必要です」、または「N文字列での繰り返しを避けたいので、衝突のn分の1のリスクを受け入れることができます」に沿った何か。いずれにせよ、それは直接エントロピーについてであり、間接的に文字列の長さについてのみです。

たとえば、@ Gjaldon 'のようなソリューションを使用する場合、512ビットのランダム性を使用しても理解できることを確認してください。random_string(64)によって生成される実際の文字列のエントロピーの量は320ビットです。もちろん、それが十分かどうかはシナリオによって異なります。上記のように、たとえば、「1兆分の1以下の反復のリスクがある100万の文字列が必要です」と表現するのが最善です。この場合、320ビットは必要なのは79だけなので、過剰な過剰です。

ランダム文字列の生成をさらに制御および理解する必要がある場合は、 EntropyString を参照してください。このライブラリを使用すると、次のような操作を行って、256ビットのエントロピーを持つ文字列を取得できます。

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

または、1兆分の1の繰り返しリスクで100万の文字列で十分であることがわかった場合、次のように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"

いずれにせよ、制御と理解は素晴らしいものです。

4
dingo sky