Skip to content

Commit c37e67a

Browse files
committed
feat: sign_in and sign_up generate jwt
1 parent ea9ae8c commit c37e67a

6 files changed

Lines changed: 59 additions & 21 deletions

File tree

lib/api_ecommerce/auth.ex

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ defmodule ApiEcommerce.Auth do
44
"""
55

66
import Ecto.Query, warn: false
7-
alias ApiEcommerce.Repo
87

8+
alias ApiEcommerce.Repo
99
alias ApiEcommerce.Auth.User
10+
alias ApiEcommerce.Guardian
1011

1112
@doc """
1213
Returns the list of users.
@@ -107,6 +108,7 @@ defmodule ApiEcommerce.Auth do
107108
query
108109
|> Repo.one()
109110
|> verify_password(password)
111+
|> gen_token()
110112
end
111113

112114
defp verify_password(nil, _) do
@@ -116,9 +118,20 @@ defmodule ApiEcommerce.Auth do
116118

117119
defp verify_password(user, password) do
118120
if Bcrypt.verify_pass(password, user.password_hash) do
119-
{:ok, user}
121+
user
120122
else
121123
{:error, "Wrong username or password"}
122124
end
123125
end
126+
127+
defp gen_token(%User{} = user) do
128+
case Guardian.encode_and_sign(user) do
129+
{:ok, token, _claims} -> {:ok, user, token}
130+
_ -> {:error, :unauthorized}
131+
end
132+
end
133+
134+
defp gen_token(error) do
135+
error
136+
end
124137
end

lib/api_ecommerce_web/controllers/user_controller.ex

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ defmodule ApiEcommerceWeb.UserController do
33

44
alias ApiEcommerce.Auth
55
alias ApiEcommerce.Auth.User
6+
alias ApiEcommerce.Guardian
67

78
action_fallback ApiEcommerceWeb.FallbackController
89

910
def index(conn, _params) do
1011
users = Auth.list_users()
11-
user = get_session(conn, :current_user_id)
12-
render(conn, "index.json", users: users, user: user)
12+
render(conn, "index.json", users: users)
1313
end
1414

1515
def create(conn, %{"user" => user_params}) do
16-
with {:ok, %User{} = user} <- Auth.create_user(user_params) do
16+
with {:ok, %User{} = user} <- Auth.create_user(user_params),
17+
{:ok, token, _claims} <- Guardian.encode_and_sign(user) do
1718
conn
1819
|> put_status(:created)
1920
|> put_resp_header("location", Routes.user_path(conn, :show, user))
20-
|> render("show.json", user: user)
21+
|> render("sign_up.json", user: user, token: token)
2122
end
2223
end
2324

@@ -44,11 +45,11 @@ defmodule ApiEcommerceWeb.UserController do
4445

4546
def sign_in(conn, %{"email" => email, "password" => password}) do
4647
case ApiEcommerce.Auth.authenticate_user(email, password) do
47-
{:ok, user} ->
48+
{:ok, user, token} ->
4849
conn
4950
|> put_status(:ok)
5051
|> put_view(ApiEcommerceWeb.UserView)
51-
|> render("sign_in.json", user: user)
52+
|> render("sign_in.json", user: user, token: token)
5253

5354
{:error, message} ->
5455
conn

lib/api_ecommerce_web/views/user_view.ex

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ defmodule ApiEcommerceWeb.UserView do
22
use ApiEcommerceWeb, :view
33
alias ApiEcommerceWeb.UserView
44

5-
def render("index.json", %{users: users, user: user}) do
6-
%{
7-
data: render_many(users, UserView, "user.json"),
8-
user: user
9-
}
5+
def render("index.json", %{users: users}) do
6+
%{data: render_many(users, UserView, "user.json")}
107
end
118

129
def render("show.json", %{user: user}) do
1310
%{data: render_one(user, UserView, "user.json")}
1411
end
1512

16-
def render("sign_in.json", %{user: user}) do
17-
%{data: render_one(user, UserView, "user.json")}
13+
def render("sign_in.json", %{user: user, token: token}) do
14+
%{data: Map.merge(render_one(user, UserView, "user.json"), %{token: token})}
15+
end
16+
17+
def render("sign_up.json", %{user: user, token: token}) do
18+
%{data: Map.merge(render_one(user, UserView, "user.json"), %{token: token})}
1819
end
1920

2021
def render("user.json", %{user: user}) do

lib/guardian.ex

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
defmodule ApiEcommerce.Guardian do
2+
use Guardian, otp_app: :api_ecommerce
3+
4+
def subject_for_token(user, _claims) do
5+
sub = to_string(user.id)
6+
{:ok, sub}
7+
end
8+
9+
def subject_for_token(_, _) do
10+
{:error, :reason_for_error}
11+
end
12+
13+
def resource_from_claims(claims) do
14+
id = claims["sub"]
15+
resource = MyApi.Accounts.get_user!(id)
16+
{:ok, resource}
17+
end
18+
19+
def resource_from_claims(_claims) do
20+
{:error, :reason_for_error}
21+
end
22+
end

test/api_ecommerce/auth_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ defmodule ApiEcommerce.AuthTest do
8787
test "authenticate_user/2 authenticates the user" do
8888
user = user_fixture()
8989
assert {:error, "Wrong username or password"} = Auth.authenticate_user("wrong email", "")
90-
assert {:ok, authenticated_user} = Auth.authenticate_user(user.email, @valid_attrs.password)
90+
assert {:ok, authenticated_user, token} = Auth.authenticate_user(user.email, @valid_attrs.password)
9191
assert %{user | password: nil, password_confirmation: nil} == authenticated_user
9292
end
9393
end

test/api_ecommerce_web/controllers/user_controller_test.exs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule ApiEcommerceWeb.UserControllerTest do
33

44
alias ApiEcommerce.Auth
55
alias ApiEcommerce.Auth.User
6+
alias ApiEcommerce.Guardian
67

78
@create_attrs %{
89
email: "some@email",
@@ -112,11 +113,11 @@ defmodule ApiEcommerceWeb.UserControllerTest do
112113
conn =
113114
post(conn, Routes.user_path(conn, :sign_in, %{ email: current_user.email, password: @current_user_attrs.password}))
114115

115-
assert json_response(conn, 200)["data"] == %{
116-
"id" => current_user.id,
117-
"email" => current_user.email,
118-
"status" => current_user.status |> Atom.to_string(),
119-
"role" => current_user.role |> Atom.to_string()}
116+
assert json_response(conn, 200)["data"]["id"] == current_user.id
117+
assert json_response(conn, 200)["data"]["email"] == current_user.email
118+
assert json_response(conn, 200)["data"]["status"] == current_user.status |> Atom.to_string()
119+
assert json_response(conn, 200)["data"]["role"] == current_user.role |> Atom.to_string()
120+
assert {:ok, claims} = Guardian.decode_and_verify(json_response(conn, 200)["data"]["token"])
120121
end
121122

122123
test "renders errors when user credentials are bad", %{conn: conn} do

0 commit comments

Comments
 (0)