无法理解JWT auth(Phoenix)中的解构 [英] Can't understand destructuring in JWT auth (Phoenix)
问题描述
我正在设置一种模式,在Phoenix中使用Comeonin和Guardian进行JWT身份验证时,已经在API身份验证中看到了一些地方.
I'm setting up a pattern that I've seen a few places for API authentication in Phoenix, using Comeonin and Guardian for JWT auth.
当我从CURL发布到MyApp.SessionsController.create/2
时,正如我期望的那样,我从MyApp.Session.authenticate/1
返回了user
响应.但是,我应该将其分解为{:ok, jwt, _full_claims}
,然后可以将其通过管道传递给Guardian.我使用IO.inspect user
查看user
对象并得到以下错误:
When I POST to MyApp.SessionsController.create/2
from CURL, I get a user
response back from MyApp.Session.authenticate/1
as I would expect. However, I'm supposed to destructure it into {:ok, jwt, _full_claims}
, which can then be piped to Guardian. I use IO.inspect user
to look at the user
object and get the following error:
端子:
curl -H "Content-Type: application/json" -X POST -d '{"email":"me@myapp.com","password":"password", "session":{"email":"mark@myapp.com", "password":"password"}}' http://localhost:4000/api/v1/sessions
当我在IEX中IO.inspect
user
时,我看到以下内容:
When I IO.inspect
the user
in IEX I see this:
%MyApp.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, avatar_url: nil,
email: "me@myapp.com", handle: "me", id: 2,
inserted_at: ~N[2017-08-22 18:26:10.000033], password: nil,
password_hash: "$2b$12$LpJTWWEEUzrkkzu2w9sRheGHkh0YOgUIOkLluk05StlmTP6EiyPA6",
updated_at: ~N[2017-08-22 18:26:10.007796]}
我看到这个错误:
Request: POST /api/v1/sessions
** (exit) an exception was raised:
** (MatchError) no match of right hand side value: %MyApp.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, avatar_url: nil, email: "me@myapp.com", handle: "mark", id: 2, inserted_at: ~N[2017-08-22 18:26:10.000033], password: nil, password_hash: "$2b$12$LpJTWWEEUzrkkzu2w9sRheGHkh0YOgUIOkLluk05StlmTP6EiyPA6", updated_at: ~N[2017-08-22 18:26:10.007796]}
(myapp) web/controllers/api/v1/sessions_controller.ex:11: MyApp.SessionsController.create/2
这到底是什么意思:{:ok, jwt, _full_claims} = user
?
这是设置:
What exactly does this mean: {:ok, jwt, _full_claims} = user
?
Here's the setup:
# mix.exs
defp deps do
[
{:distillery, "~> 1.4", runtime: false},
{:phoenix, "~> 1.3.0-rc", override: true},
{:phoenix_ecto, "~> 3.2"},
...
{:comeonin, "~> 4.0"},
{:bcrypt_elixir, "~> 0.12.0"},
{:guardian, "~> 0.14.5"},
]
# web/router.ex
...
pipeline :api do
plug :accepts, ["json"]
plug Guardian.Plug.VerifyHeader
end
scope "/api", MyApp do
pipe_through :api
scope "/v1" do
post "/sessions", SessionsController, :create
end
end
...
# web/controllers/session_controller.ex
defmodule MyApp.SessionsController do
use MyApp.Web, :controller
alias MyApp.{Repo, User}
plug :scrub_params, "session" when action in [:create]
def create(conn, %{"session" => session_params}) do
case MyApp.Session.authenticate(session_params) do
{:ok, user} ->
{:ok, jwt, _full_claims} = user
IO.inspect user # Trying to test it here
|> Guardian.encode_and_sign(:token)
conn
|> put_status(:created)
|> render("show.json", jwt: jwt, user: user)
:error ->
conn
|> put_status(:unprocessable_entity)
|> render("error.json")
end
end
# web/services/session.ex
defmodule MyApp.Session do
alias MyApp.{Repo, User}
import Bcrypt
def authenticate(%{"email" => email, "password" => password}) do
case Repo.get_by(User, email: email) do
nil ->
:error
user ->
case verify_password(password, user.password_hash) do
true ->
{:ok, user}
_ ->
:error
end
end
end
defp verify_password(password, pw_hash) do
Comeonin.Bcrypt.checkpw(password, pw_hash)
end
end
# lib/MyApp/User.ex
defmodule MyApp.User do
use MyApp.Web, :model
schema "users" do
field :email, :string
field :handle, :string
field :password_hash, :string
field :avatar_url, :string
field :password, :string, virtual: true
timestamps
end
def changeset(model, params \\ :empty) do
model
|> cast(params, [:email, :handle, :password_hash, :password, :avatar_url])
|> validate_required([:email])
|> validate_length(:email, min: 1, max: 255)
|> validate_format(:email, ~r/@/)
end
添加监护人信息
Adding Guardian info
#config/config.exs
config :guardian, Guardian,
issuer: "MyApp",
ttl: { 30, :days},
verify_issuer: true,
secret_key: "abc123",
serializer: MyApp.GuardianSerializer
#lib/MyApp/guardian_serializer.ex
defmodule MyApp.GuardianSerializer do
@behaviour Guardian.Serializer
alias MyApp.Repo
alias MyApp.User
def for_token(user = %User{}), do: {:ok, "User:#{user.id}"}
def for_token(_), do: {:error, "Unknown resource type"}
def from_token("User:" <> id), do: {:ok, Repo.get(User, id)}
def from_token(_), do: {:error, "Unknown resource type"}
end
推荐答案
{:ok, jwt, _full_claims}
是通过调用Guardian.encode_and_sign(user, :token)
返回的值.这是您链接到的教程中的原始代码:
{:ok, jwt, _full_claims}
is the value that's returned by calling Guardian.encode_and_sign(user, :token)
. This is the original code in the tutorial you linked to:
{:ok, jwt, _full_claims} = user
|> Guardian.encode_and_sign(:token)
与以下相同:
{:ok, jwt, _full_claims} = Guardian.encode_and_sign(user, :token)
另一方面,您的代码执行{:ok, jwt, _full_claims} = user
,下一行是新语句.如果您想检查用户并仍然执行本教程的操作,则可以执行以下操作:
Your code on the other hand does {:ok, jwt, _full_claims} = user
and the next line is a new statement. If you want to inspect the user and still do what the tutorial does, you can do:
{:ok, jwt, _full_claims} = user
|> IO.inspect
|> Guardian.encode_and_sign(:token)
IO.inspect
返回打印后传递的值,因此该代码的功能与教程相同,除了它还将打印user
的值.
IO.inspect
returns the value that's passed after printing it, so this code will function identical to the tutorial except that it'll print the value of user
as well.
这篇关于无法理解JWT auth(Phoenix)中的解构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!