【问题标题】:Elixir/Phoenix restrict params like Rails strong paramsElixir/Phoenix 限制参数,如 Rails 强参数
【发布时间】:2017-02-17 17:26:50
【问题描述】:

我正在制作一个仅 API 的 Phoenix 应用程序。我来自 Ruby on Rails 背景,请耐心等待。

假设我有一个带有 emailpasswordpassword_hashrole 字段的用户模型。

我需要限制用户输入的 rolepassword_hash 字段,或者将 emailpassword 字段列入白名单。现在任何人都可以以管理员身份发布此注册:

{
    "user": {
        "email": "test3@test.com",
        "password": "testpw",
        "password_hash": "shouldn't allow user input",
        "role": "admin"
    }
}

这通常在 Rails 中使用强参数来完成,这将去除未明确指定的字段。

如何使用最佳实践对 Phoenix 进行限制/白名单参数?

这是我的 user_controller 中的创建方法:

  def create(conn, %{"user" => user_params}) do
    changeset = User.registration_changeset(%User{}, user_params)
    ...
    ...
  end

这是我在模型 user.ex 中的架构和变更集。我关注this tutorial, it says "we pipe the new changeset through our original one"

  schema "users" do
    field :email, :string
    field :password, :string, virtual: true
    field :password_hash, :string
    field :role, :string

    timestamps()
  end

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, ~w(email), [])
    |> downcase_email()
    |> unique_constraint(:email)
    |> validate_format(:email, ~r/@/)
  end

  def registration_changeset(model, params) do
    model
    |> changeset(params)
    |> cast(params, ~w(password), [])
    |> validate_length(:password, min: 6)
    |> put_password_hash()
  end

Phoenix 的 scrub_params is close,但听起来不像我需要的。

我想我可以通过模式匹配来实现这一点,但我不确定如何。

【问题讨论】:

  • cast 不起作用很奇怪,因为它应该完全按照您的要求执行:只允许 email 参数。此外,您的控制器正在使用User.registration_changeset/2,但您向我们展示了User.changeset/2 的代码。
  • 您的registration_changeset 是什么样的?您的changeset 应该已经忽略了params 中的role 字段。
  • 我还建议使用cast/3 而不是cast/4,因为后者已被弃用。
  • 感谢@tompave 的回复,我已经用registration_changeset 修改了我的问题。它肯定至少允许角色字段通过并被保存。另外,我使用单独的迁移添加了角色字段,但这应该没有区别吗?

标签: elixir phoenix-framework ecto


【解决方案1】:

实际上代码的行为符合预期,并没有保存角色字段。 (我是在控制台中读取请求,而不是实际检查数据库。)

【讨论】:

  • 感谢您的反馈。您应该更新问题(以便搜索类似问题的人可以更轻松地找到信息)或关闭它。
【解决方案2】:

我知道这已经很晚了,但这是这种方法:

defmodule MyApp.Utils do
  def strong_params(params, allowed_fields) when is_map(params) do
    allowed_strings = Enum.map(allowed_fields, &Atom.to_string(&1))

    Enum.reduce(params, [], fn {k, v}, acc ->
      key = check_key(k, allowed_strings)
      acc ++ [{key, v}]
    end)
    |> Enum.reject(fn {k, _v} -> k == nil end)
    |> Map.new()
  end

  defp check_key(k, allowed_strings) when is_atom(k) do
    str_key = Atom.to_string(k)

    if str_key in allowed_strings do
      k
    end
  end
  defp check_key(k, allowed_strings) when is_binary(k) do
    if k in allowed_strings do
      String.to_existing_atom(k)
    end
  end
  defp check_key(_, _), do: nil
end

参考: https://medium.com/@alves.lcs/phoenix-strong-params-9db4bd9f56d8

【讨论】:

    猜你喜欢
    • 2017-03-16
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    相关资源
    最近更新 更多