diff --git a/CHANGELOG.org b/CHANGELOG.org index fc50008..0063100 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -51,3 +51,5 @@ Add dependencies for API Authentication. ** 0.6.0 <2023-08-05 Sat> Add User model. +** 0.7.0 <2023-08-05 Sat> + Add the API Authentication. diff --git a/config/config.exs b/config/config.exs index e01ef23..cb4bbb8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -47,6 +47,10 @@ config :logger, :console, # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason +config :link_shortener, LinkShortenerWeb.Auth.Guardian, + issuer: "link_shortener", + secret_key: System.get_env("SECRET_KEY_BASE") + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/lib/link_shortener_web/auth/guardian.ex b/lib/link_shortener_web/auth/guardian.ex new file mode 100644 index 0000000..48e1bba --- /dev/null +++ b/lib/link_shortener_web/auth/guardian.ex @@ -0,0 +1,16 @@ +defmodule LinkShortenerWeb.Auth.Guardian do + use Guardian, otp_app: :link_shortener + + alias LinkShortener.Accounts + + def subject_for_token(user, _claims) do + sub = to_string(user.id) + {:ok, sub} + end + + def resource_from_claims(claims) do + id = claims["sub"] + resource = Accounts.get_user!(id) + {:ok, resource} + end +end diff --git a/lib/link_shortener_web/controllers/api/v1/user_controller.ex b/lib/link_shortener_web/controllers/api/v1/user_controller.ex index 5b2f807..cf1a7a3 100644 --- a/lib/link_shortener_web/controllers/api/v1/user_controller.ex +++ b/lib/link_shortener_web/controllers/api/v1/user_controller.ex @@ -3,41 +3,24 @@ defmodule LinkShortenerWeb.Api.V1.UserController do alias LinkShortener.Accounts alias LinkShortener.Accounts.User + alias LinkShortenerWeb.Auth.Guardian action_fallback LinkShortenerWeb.FallbackController - def index(conn, _params) do - users = Accounts.list_users() - render(conn, "index.json", users: users) - end - def create(conn, %{"user" => user_params}) do - with {:ok, %User{} = user} <- Accounts.create_user(user_params) do + with {:ok, %User{} = user} <- Accounts.create_user(user_params), + {:ok, token, _claims} <- Guardian.encode_and_sign(user) do conn |> put_status(:created) - |> put_resp_header("location", Routes.v1_user_path(conn, :show, user)) - |> render("show.json", user: user) + |> render("user.json", %{user: user, token: token}) end end - def show(conn, %{"id" => id}) do - user = Accounts.get_user!(id) - render(conn, "show.json", user: user) - end - - def update(conn, %{"id" => id, "user" => user_params}) do - user = Accounts.get_user!(id) - - with {:ok, %User{} = user} <- Accounts.update_user(user, user_params) do - render(conn, "show.json", user: user) - end - end - - def delete(conn, %{"id" => id}) do - user = Accounts.get_user!(id) - - with {:ok, %User{}} <- Accounts.delete_user(user) do - send_resp(conn, :no_content, "") + def signin(conn, %{"email" => email, "password" => password}) do + with {:ok, user, token} <- Guardian.authenticate(email, password) do + conn + |> put_status(:created) + |> render("user.json", %{user: user, token: token}) end end end diff --git a/lib/link_shortener_web/router.ex b/lib/link_shortener_web/router.ex index 303d7ff..db4401d 100644 --- a/lib/link_shortener_web/router.ex +++ b/lib/link_shortener_web/router.ex @@ -27,6 +27,8 @@ defmodule LinkShortenerWeb.Router do scope "/v1", Api.V1, as: :v1 do resources "/links", LinkController + post "/users/signup", UserController, :create + post "/users/signin", UserController, :signin end end diff --git a/lib/link_shortener_web/views/api/v1/user_view.ex b/lib/link_shortener_web/views/api/v1/user_view.ex index 5ed9ac0..dafa1f7 100644 --- a/lib/link_shortener_web/views/api/v1/user_view.ex +++ b/lib/link_shortener_web/views/api/v1/user_view.ex @@ -1,20 +1,12 @@ defmodule LinkShortenerWeb.Api.V1.UserView do use LinkShortenerWeb, :view - alias LinkShortenerWeb.UserView - def render("index.json", %{users: users}) do - %{data: render_many(users, UserView, "user.json")} - end - - def render("show.json", %{user: user}) do - %{data: render_one(user, UserView, "user.json")} - end + alias LinkShortenerWeb.Api.V1.UserView - def render("user.json", %{user: user}) do + def render("user.json", %{user: user, token: token}) do %{ - id: user.id, email: user.email, - encrypted_password: user.encrypted_password + token: token } end end