Update the API Authentication.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
32ea2c4ff8
commit
8697be9f17
@ -0,0 +1,11 @@
|
||||
defmodule LinkShortenerWeb.Auth.ErrorHandler do
|
||||
import Plug.Conn
|
||||
|
||||
def auth_error(conn, {type, _reason}, _opts) do
|
||||
body = Poison.encode!(%{error: to_string(type)})
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(401, body)
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,31 @@
|
||||
defmodule LinkShortenerWeb.Auth.Guardian do
|
||||
use Guardian, otp_app: :link_shortener
|
||||
|
||||
alias LinkShortener.Accounts
|
||||
alias LinkShortener.Accounts.User
|
||||
|
||||
def subject_for_token(user, _claims) do
|
||||
{:ok, to_string(user.id)}
|
||||
end
|
||||
|
||||
def resource_from_claims(%{"sub" => id}) do
|
||||
user = Accounts.get_user!(id)
|
||||
{:ok, user}
|
||||
rescue
|
||||
Ecto.NoResultsError -> {:error, :resource_not_found}
|
||||
end
|
||||
|
||||
def authenticate(email, password) do
|
||||
with user <- Accounts.get_user_by_email_and_password(email, password) do
|
||||
case user do
|
||||
%User{} -> create_token(user)
|
||||
nil -> {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp create_token(user) do
|
||||
{:ok, token, _claims} = encode_and_sign(user)
|
||||
{:ok, user, token}
|
||||
end
|
||||
end
|
@ -0,0 +1,9 @@
|
||||
defmodule LinkShortenerWeb.Auth.Pipeline do
|
||||
use Guardian.Plug.Pipeline, otp_app: :link_shortener,
|
||||
module: LinkShortenerWeb.Auth.Guardian,
|
||||
error_handler: LinkShortenerWeb.Auth.ErrorHandler
|
||||
|
||||
plug Guardian.Plug.VerifyHeader
|
||||
plug Guardian.Plug.EnsureAuthenticated
|
||||
plug Guardian.Plug.LoadResource
|
||||
end
|
@ -0,0 +1,26 @@
|
||||
defmodule LinkShortenerWeb.Api.V1.AccountsController do
|
||||
use LinkShortenerWeb, :controller
|
||||
|
||||
alias LinkShortener.Accounts
|
||||
alias LinkShortener.Accounts.User
|
||||
alias LinkShortenerWeb.Auth.Guardian
|
||||
|
||||
action_fallback LinkShortenerWeb.FallbackController
|
||||
|
||||
def sign_up(conn, %{"user" => user_params}) do
|
||||
with {:ok, %User{} = user} <- Accounts.register_user(user_params),
|
||||
{:ok, token, _claims} <- Guardian.encode_and_sign(user) do
|
||||
conn
|
||||
|> put_status(:created)
|
||||
|> render(:user, %{user: user, token: token})
|
||||
end
|
||||
end
|
||||
|
||||
def sign_in(conn, %{"email" => email, "password" => password}) do
|
||||
with {:ok, user, token} <- Guardian.authenticate(email, password) do
|
||||
conn
|
||||
|> put_status(:created)
|
||||
|> render(:user, %{user: user, token: token})
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,11 @@
|
||||
defmodule LinkShortenerWeb.Api.V1.AccountsJSON do
|
||||
alias LinkShortener.Links.Link
|
||||
|
||||
def user(%{user: user, token: token}) do
|
||||
%{
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
token: token
|
||||
}
|
||||
end
|
||||
end
|
@ -0,0 +1,71 @@
|
||||
defmodule LinkShortenerWeb.Api.V1.AccountsControllerTest do
|
||||
use LinkShortenerWeb.ConnCase
|
||||
|
||||
import LinkShortener.AccountsFixtures
|
||||
|
||||
alias LinkShortener.Accounts.User
|
||||
|
||||
@create_attrs %{
|
||||
email: "user@mail.com",
|
||||
password: "some password"
|
||||
}
|
||||
|
||||
@update_attrs %{
|
||||
email: "some updated email",
|
||||
password: "some updated password"
|
||||
}
|
||||
|
||||
@invalid_password_attrs %{
|
||||
email: "user@mail.com",
|
||||
password: ""
|
||||
}
|
||||
|
||||
@invalid_attrs %{
|
||||
email: nil,
|
||||
encrypted_password: nil
|
||||
}
|
||||
|
||||
setup %{conn: conn} do
|
||||
{:ok, conn: put_req_header(conn, "accept", "application/json")}
|
||||
end
|
||||
|
||||
describe "create user with sign up" do
|
||||
test "renders user when data is valid", %{conn: conn} do
|
||||
conn = post(conn, ~p"/api/v1/users/sign_up", user: @create_attrs)
|
||||
assert %{
|
||||
"email" => "user@mail.com",
|
||||
"token" => token
|
||||
} = json_response(conn, 201)
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn} do
|
||||
conn = post(conn, ~p"/api/v1/users/sign_up", user: @invalid_attrs)
|
||||
assert json_response(conn, 422)["errors"] != %{}
|
||||
end
|
||||
end
|
||||
|
||||
describe "user sign in" do
|
||||
setup [:create_user]
|
||||
|
||||
test "renders user when data is valid", %{conn: conn} do
|
||||
conn = post(conn, ~p"/api/v1/users/sign_in", @create_attrs)
|
||||
|
||||
assert %{
|
||||
"email" => email,
|
||||
"token" => token,
|
||||
} = json_response(conn, 201)
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn} do
|
||||
conn = post(conn, ~p"/api/v1/users/sign_in", @invalid_password_attrs)
|
||||
assert %{
|
||||
"errors" => %{"detail" => "Unauthorized"}
|
||||
} = json_response(conn, 401)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_user(_) do
|
||||
user = user_fixture(@create_attrs)
|
||||
%{user: user}
|
||||
end
|
||||
end
|
Loading…
Reference in new issue