我正在制作一个仅限API的应用程序。我来自Ruby on Rails背景,所以请耐心等待。
假设我的用户模型包含email
,password
,password_hash
和role
字段。
我需要限制用户输入中的role
和password_hash
字段,或将email
和password
字段列入白名单。现在任何人都可以将这个注册作为管理员注册:
{
"user": {
"email": "test3@test.com",
"password": "testpw",
"password_hash": "shouldn't allow user input",
"role": "admin"
}
}
这通常使用强参数在Rails中完成,这将删除未明确指定的字段。
如何使用最佳做法限制/列入凤凰城的参数?
这是我在user_controller中的create方法:
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
凤凰城的scrub_params is close,但它听起来并不像我需要的。
我认为我可以通过模式匹配来实现这一目标,但我不确定如何。
答案 0 :(得分:0)
实际上代码的行为与预期的一样,并没有保存角色字段。 (我在控制台中读取请求,而不是实际检查数据库。)
答案 1 :(得分:0)
我知道这已经很晚了,但这是方法:
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