Add authentication for web frontend
This commit is contained in:
parent
074e208174
commit
13d7f832fe
|
@ -29,7 +29,7 @@ defmodule Clacks.Actor do
|
||||||
|
|
||||||
@spec get_by_nickname(nickname :: String.t()) :: t() | nil
|
@spec get_by_nickname(nickname :: String.t()) :: t() | nil
|
||||||
def get_by_nickname(nickname) do
|
def get_by_nickname(nickname) do
|
||||||
Repo.one(from a in __MODULE__, where: a.nickname == ^nickname)
|
Repo.get_by(__MODULE__, nickname: nickname)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_by_ap_id(ap_id :: String.t(), force_refetch :: boolean()) :: t() | nil
|
@spec get_by_ap_id(ap_id :: String.t(), force_refetch :: boolean()) :: t() | nil
|
||||||
|
@ -43,7 +43,7 @@ defmodule Clacks.Actor do
|
||||||
|
|
||||||
@spec get_cached_by_ap_id(ap_id :: String.t()) :: t() | nil
|
@spec get_cached_by_ap_id(ap_id :: String.t()) :: t() | nil
|
||||||
def get_cached_by_ap_id(ap_id) do
|
def get_cached_by_ap_id(ap_id) do
|
||||||
Repo.one(from a in __MODULE__, where: a.ap_id == ^ap_id)
|
Repo.get_by(__MODULE__, ap_id: ap_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec fetch(ap_id :: String.t()) :: t() | nil
|
@spec fetch(ap_id :: String.t()) :: t() | nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
defmodule Clacks.User do
|
defmodule Clacks.User do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
alias Clacks.Repo
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
@type t() :: %__MODULE__{}
|
||||||
|
|
||||||
|
@ -40,4 +41,8 @@ defmodule Clacks.User do
|
||||||
) do
|
) do
|
||||||
change(changeset, Bcrypt.add_hash(password))
|
change(changeset, Bcrypt.add_hash(password))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_by_username(username) do
|
||||||
|
Repo.get_by(__MODULE__, username: username)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
defmodule ClacksWeb.LoginController do
|
||||||
|
use ClacksWeb, :controller
|
||||||
|
alias Clacks.User
|
||||||
|
alias ClacksWeb.Router.Helpers, as: Routes
|
||||||
|
alias ClacksWeb.Endpoint
|
||||||
|
|
||||||
|
def login(conn, params) do
|
||||||
|
render(conn, "login.html", %{
|
||||||
|
continue: Map.get(params, "continue")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
def login_post(conn, %{"username" => username, "password" => password} = params) do
|
||||||
|
user = User.get_by_username(username)
|
||||||
|
|
||||||
|
case Bcrypt.check_pass(user, password) do
|
||||||
|
{:ok, user} ->
|
||||||
|
user_token = Phoenix.Token.sign(Endpoint, "user token", user.id)
|
||||||
|
redirect_uri = Map.get(params, "continue") || "/"
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_session(:user_token, user_token)
|
||||||
|
|> redirect(to: redirect_uri)
|
||||||
|
|
||||||
|
{:error, _reason} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Invalid username or password.")
|
||||||
|
|> redirect(to: Routes.login_path(Endpoint, :login))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def login_post(conn, _params) do
|
||||||
|
redirect(conn, to: Routes.login_path(Endpoint, :login))
|
||||||
|
end
|
||||||
|
|
||||||
|
def logout(conn, _params) do
|
||||||
|
conn
|
||||||
|
|> clear_session()
|
||||||
|
|> put_flash(:info, "Logged out.")
|
||||||
|
|> redirect(to: "/")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,41 @@
|
||||||
|
defmodule ClacksWeb.Plug.WebAuthenticate do
|
||||||
|
import Plug.Conn
|
||||||
|
alias Clacks.{Repo, User}
|
||||||
|
alias ClacksWeb.Router.Helpers, as: Routes
|
||||||
|
alias ClacksWeb.Endpoint
|
||||||
|
|
||||||
|
def init(%{on_failure: on_failure_action} = opts)
|
||||||
|
when on_failure_action in [:redirect_to_login, :pass],
|
||||||
|
do: opts
|
||||||
|
|
||||||
|
def init(_), do: %{on_failure: :redirect_to_login}
|
||||||
|
|
||||||
|
def call(conn, %{on_failure: on_failure_action}) do
|
||||||
|
user_token = get_session(conn, :user_token)
|
||||||
|
|
||||||
|
case Phoenix.Token.verify(Endpoint, "user token", user_token, max_age: 7 * 24 * 60 * 60) do
|
||||||
|
{:error, _reason} ->
|
||||||
|
on_failure(conn, on_failure_action)
|
||||||
|
|
||||||
|
{:ok, user_id} ->
|
||||||
|
case Repo.get(User, user_id) do
|
||||||
|
nil ->
|
||||||
|
on_failure(conn, on_failure_action)
|
||||||
|
|
||||||
|
user ->
|
||||||
|
user = Repo.preload(user, :actor)
|
||||||
|
assign(conn, :user, user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp on_failure(conn, :redirect_to_login) do
|
||||||
|
conn
|
||||||
|
|> Phoenix.Controller.redirect(to: Routes.login_path(Endpoint, :login))
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp on_failure(conn, :pass) do
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,6 +7,11 @@ defmodule ClacksWeb.Router do
|
||||||
plug :fetch_flash
|
plug :fetch_flash
|
||||||
plug :protect_from_forgery
|
plug :protect_from_forgery
|
||||||
plug :put_secure_browser_headers
|
plug :put_secure_browser_headers
|
||||||
|
plug ClacksWeb.Plug.WebAuthenticate, on_failure: :pass
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline :browser_authenticated do
|
||||||
|
plug ClacksWeb.Plug.WebAuthenticate, on_failure: :redirect_to_login
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :activitypub do
|
pipeline :activitypub do
|
||||||
|
@ -15,6 +20,15 @@ defmodule ClacksWeb.Router do
|
||||||
|
|
||||||
scope "/", ClacksWeb do
|
scope "/", ClacksWeb do
|
||||||
pipe_through :browser
|
pipe_through :browser
|
||||||
|
|
||||||
|
get "/login", LoginController, :login
|
||||||
|
post "/login", LoginController, :login_post
|
||||||
|
post "/logout", LoginController, :logout_post
|
||||||
|
end
|
||||||
|
|
||||||
|
scope "/", ClacksWeb do
|
||||||
|
pipe_through :browser
|
||||||
|
pipe_through :browser_authenticated
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", ClacksWeb do
|
scope "/", ClacksWeb do
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<%= form_tag Routes.login_path(@conn, :login_post), method: :post do %>
|
||||||
|
<%= if @continue do %>
|
||||||
|
<input type="hidden" name="continue" value="<%= @continue %>">
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input id="username" type="text" name="username">
|
||||||
|
<br>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input id="password" type="password" name="password">
|
||||||
|
<br>
|
||||||
|
<%= submit "Log In" %>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule ClacksWeb.PageView do
|
||||||
|
use ClacksWeb, :view
|
||||||
|
end
|
|
@ -1,3 +1,3 @@
|
||||||
defmodule ClacksWeb.PageView do
|
defmodule ClacksWeb.LoginView do
|
||||||
use ClacksWeb, :view
|
use ClacksWeb, :view
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue