Elixir/Phoenix 限制参数,例如 Rails 强参数
Elixir/Phoenix restrict params like Rails strong params
我正在制作 API 唯一的 Phoenix 应用程序。我来自 Ruby Rails 背景,请耐心等待。
假设我有一个包含 email
、password
、password_hash
和 role
字段的用户模型。
我需要限制用户输入的 role
和 password_hash
字段,或者将 email
和 password
字段列入白名单。现在任何人都可以POST注册成为管理员:
{
"user": {
"email": "test3@test.com",
"password": "testpw",
"password_hash": "shouldn't allow user input",
"role": "admin"
}
}
这通常是在 Rails 中使用强参数完成的,这将去除未明确指定的字段。
如何使用最佳实践对 Phoenix 进行 restrict/whitelist 参数设置?
这是我在 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 的 ,但听起来不像我需要的。
我想我可以通过模式匹配来完成这个,但我不确定如何。
实际上代码的行为符合预期,没有保存角色字段。 (我是在控制台中读取请求,而不是实际检查数据库。)
我知道这已经晚了,但这是这种方法:
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
Reference:
https://medium.com/@alves.lcs/phoenix-strong-params-9db4bd9f56d8
我正在制作 API 唯一的 Phoenix 应用程序。我来自 Ruby Rails 背景,请耐心等待。
假设我有一个包含 email
、password
、password_hash
和 role
字段的用户模型。
我需要限制用户输入的 role
和 password_hash
字段,或者将 email
和 password
字段列入白名单。现在任何人都可以POST注册成为管理员:
{
"user": {
"email": "test3@test.com",
"password": "testpw",
"password_hash": "shouldn't allow user input",
"role": "admin"
}
}
这通常是在 Rails 中使用强参数完成的,这将去除未明确指定的字段。
如何使用最佳实践对 Phoenix 进行 restrict/whitelist 参数设置?
这是我在 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 的
我想我可以通过模式匹配来完成这个,但我不确定如何。
实际上代码的行为符合预期,没有保存角色字段。 (我是在控制台中读取请求,而不是实际检查数据库。)
我知道这已经晚了,但这是这种方法:
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
Reference: https://medium.com/@alves.lcs/phoenix-strong-params-9db4bd9f56d8