我正在尝试为我的应用程序创建自定义服务器端用户身份验证。有了这个,我的意思是我在数据库中使用字段token
和字段user_id
保存会话,并且只要会话发生,就打算在conn.assigns
中访问该令牌。最后一部分是我发现了问题。应该说我是一个红宝石开发者,这是我在elixir中的第一个应用程序。
这是我的会话模型:
defmodule Prode.Session do
use Prode.Web, :model
schema "sessions" do
field :token, :string
belongs_to :user, Prode.User
timestamps()
end
@doc """
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:user_id])
|> validate_required([:user_id])
end
def create_changeset(model, params \\ %{}) do
model
|> changeset(params)
|> put_change(:token, SecureRandom.urlsafe_base64())
end
end
这里是通讯员:
defmodule Prode.SessionController do
use Prode.Web, :controller
import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0]
alias Prode.Session
alias Prode.User
def create(conn, %{"user" => user_params}) do
user = Repo.get_by(User, email: user_params["email"])
cond do
user && checkpw(user_params["password"], user.password_hash) ->
session_changeset = Session.create_changeset(%Session{}, %{user_id: user.id})
{:ok, session} = Repo.insert(session_changeset)
conn
|> assign(:token, session.token)
|> put_status(:created)
|> render("show.json", session: session)
user ->
conn
|> put_status(:unauthorized)
|> render("error.json", user_params)
true ->
dummy_checkpw
conn
|> put_status(:unauthorized)
|> render("error.json", user_params)
end
end
end
然后我创建了以下插件来确认身份验证并设置当前用户:
defmodule Prode.Authentication do
import Plug.Conn
alias Prode.{Repo, User, Session}
import Ecto.Query, only: [from: 2]
def init(options), do: options
def call(conn, _opts) do
case find_user(conn) do
{:ok, user} -> assign(conn, :current_user, user)
_otherwise -> auth_error!(conn)
end
end
defp find_user(conn) do
session = Repo.get(Session, conn.assigns.token)
case Repo.get(User, session.user_id) do
nil -> :error
session -> {:ok, session}
end
end
end
我在其他控制器上添加了这个插件:
plug Prode.Authentication
但问题是,在用户经过正确身份验证并且执行运行插件后,conn.assigns
为空:
key :token not found in: %{}