admin only pages, updated sign in page, redirects
This commit is contained in:
parent
339d075edd
commit
ef3d6d8b7a
7 changed files with 108 additions and 54 deletions
lib/cms_web
|
@ -11,7 +11,9 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="flex flex-row">
|
<section class="flex flex-row">
|
||||||
<.link href={~p"/admin/session"} method="delete" class="hover:underline">sign out</.link>
|
<.link href={~p"/admin/session/destroy?return_to=#{@current_path}"} class="hover:underline">
|
||||||
|
sign out
|
||||||
|
</.link>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col md:flex-row mx-auto max-w-4xl">
|
<div class="flex flex-col md:flex-row mx-auto max-w-4xl">
|
||||||
|
@ -28,3 +30,9 @@
|
||||||
{@inner_content}
|
{@inner_content}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
:if={not @admin?}
|
||||||
|
class="fixed right-0 bottom-0 p-2 text-transparent underline hover:text-current"
|
||||||
|
>
|
||||||
|
<.link href={~p"/sign-in?return_to=#{@current_path}"}>sign in</.link>
|
||||||
|
</div>
|
||||||
|
|
|
@ -5,21 +5,33 @@ defmodule CMSWeb.AdminAuth do
|
||||||
import Phoenix.Controller
|
import Phoenix.Controller
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
def log_in_admin(conn) do
|
def log_in_admin(conn, params) do
|
||||||
conn
|
conn
|
||||||
|> renew_session()
|
|> renew_session()
|
||||||
|> put_session(:admin?, true)
|
|> put_session(:admin?, true)
|
||||||
|> redirect(to: ~p"/")
|
|> redirect(to: params["return_to"] || ~p"/admin")
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_out_admin(conn) do
|
def log_out_admin(conn, params) do
|
||||||
if live_socket_id = get_session(conn, :live_socket_id) do
|
if live_socket_id = get_session(conn, :live_socket_id) do
|
||||||
CMSWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
|
CMSWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> renew_session()
|
|> renew_session()
|
||||||
|> redirect(to: ~p"/")
|
|> redirect(to: params["return_to"] || ~p"/")
|
||||||
|
end
|
||||||
|
|
||||||
|
def mount_admin(%Plug.Conn{} = conn, _opts) do
|
||||||
|
assign(conn, :admin?, admin?(conn))
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_admin(%Plug.Conn{assigns: %{admin?: true}} = conn, _opts) do
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_admin(conn, _opts) do
|
||||||
|
redirect(conn, to: ~p"/sign-in?return_to=#{conn.request_path}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def correct_password?(password) do
|
def correct_password?(password) do
|
||||||
|
@ -28,6 +40,10 @@ defmodule CMSWeb.AdminAuth do
|
||||||
Argon2.verify_pass(password, password_hash)
|
Argon2.verify_pass(password, password_hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on_mount(:default, _params, session, socket) do
|
||||||
|
{:cont, Phoenix.Component.assign(socket, :admin?, admin?(session))}
|
||||||
|
end
|
||||||
|
|
||||||
## private
|
## private
|
||||||
|
|
||||||
defp renew_session(conn) do
|
defp renew_session(conn) do
|
||||||
|
@ -37,4 +53,10 @@ defmodule CMSWeb.AdminAuth do
|
||||||
|> configure_session(renew: true)
|
|> configure_session(renew: true)
|
||||||
|> clear_session()
|
|> clear_session()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp admin?(%Plug.Conn{} = conn) do
|
||||||
|
Plug.Conn.get_session(conn, :admin?, false) == true
|
||||||
|
end
|
||||||
|
|
||||||
|
defp admin?(%{} = session), do: Map.get(session, "admin?", false) == true
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
defmodule CMSWeb.AdminMode do
|
|
||||||
@moduledoc false
|
|
||||||
use CMSWeb, :live_view
|
|
||||||
|
|
||||||
def admin_mode(%Plug.Conn{} = conn, _opts) do
|
|
||||||
Plug.Conn.assign(conn, :admin?, admin?(conn))
|
|
||||||
end
|
|
||||||
|
|
||||||
def on_mount(:default, _params, session, socket) do
|
|
||||||
{:cont, assign(socket, :admin?, admin?(session))}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp admin?(%Plug.Conn{} = conn) do
|
|
||||||
Plug.Conn.get_session(conn, :admin?, false) == true
|
|
||||||
end
|
|
||||||
|
|
||||||
defp admin?(%{} = session), do: Map.get(session, :admin?, false) == true
|
|
||||||
end
|
|
|
@ -3,21 +3,19 @@ defmodule CMSWeb.AdminSessionController do
|
||||||
|
|
||||||
alias CMSWeb.AdminAuth
|
alias CMSWeb.AdminAuth
|
||||||
|
|
||||||
def create(conn, %{"password" => password}) do
|
def create(conn, %{"password" => password} = params) do
|
||||||
if AdminAuth.correct_password?(password) do
|
if AdminAuth.correct_password?(password) do
|
||||||
AdminAuth.log_in_admin(conn)
|
AdminAuth.log_in_admin(conn, params)
|
||||||
else
|
else
|
||||||
redirect(conn, to: ~p"/admin/sign-in")
|
redirect(conn, to: ~p"/sign-in")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
redirect(conn, to: ~p"/admin/sign-in")
|
redirect(conn, to: ~p"/sign-in")
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy(conn, _params) do
|
def destroy(conn, params) do
|
||||||
conn
|
AdminAuth.log_out_admin(conn, params)
|
||||||
|> AdminAuth.log_out_admin()
|
|
||||||
|> redirect(to: ~p"/")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
18
lib/cms_web/controllers/globals.ex
Normal file
18
lib/cms_web/controllers/globals.ex
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
defmodule CMSWeb.Globals do
|
||||||
|
@moduledoc false
|
||||||
|
use CMSWeb, :live_view
|
||||||
|
|
||||||
|
def assign_globals(%Plug.Conn{} = conn, _opts) do
|
||||||
|
Plug.Conn.assign(conn, :current_path, conn.request_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_mount(:default, _params, _session, socket) do
|
||||||
|
socket =
|
||||||
|
attach_hook(socket, :assign_handle_params_globals, :handle_params, fn _params, uri, socket ->
|
||||||
|
%URI{path: current_path} = URI.parse(uri)
|
||||||
|
{:cont, assign(socket, :current_path, current_path)}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:cont, socket}
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,27 +3,37 @@ defmodule CMSWeb.AdminLoginLive do
|
||||||
use CMSWeb, :live_view
|
use CMSWeb, :live_view
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, _session, socket) do
|
def mount(params, _session, socket) do
|
||||||
socket = assign(socket, :form, to_form(%{"password" => ""}))
|
socket = assign(socket, :form, to_form(%{"password" => "", "return_to" => params["return_to"]}))
|
||||||
|
|
||||||
{:ok, socket}
|
{:ok, socket, layout: false}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<h1 class="font-bold text-lg mb-4">Sign in</h1>
|
<main class="flex flex-col w-screen h-screen fixed justify-center items-center">
|
||||||
|
<.form for={@form} action={~p"/admin/session/create"} class="flex flex-col gap-y-2">
|
||||||
<.form for={@form} action={~p"/admin/session"}>
|
<input
|
||||||
<input
|
type="hidden"
|
||||||
type="password"
|
id={@form[:return_to].id}
|
||||||
placeholder="password"
|
name={@form[:return_to].name}
|
||||||
id={@form[:password].id}
|
value={@form[:return_to].value}
|
||||||
name={@form[:password].name}
|
/>
|
||||||
value={@form[:password].value}
|
<input
|
||||||
required
|
type="password"
|
||||||
/>
|
placeholder="password"
|
||||||
</.form>
|
id={@form[:password].id}
|
||||||
|
name={@form[:password].name}
|
||||||
|
value={@form[:password].value}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<div class="flex flex-col items-end">
|
||||||
|
<button type="submit" class="font-bold hover:underline">sign in</button>
|
||||||
|
<.link href={~p"/"} class="hover:underline">cancel</.link>
|
||||||
|
</div>
|
||||||
|
</.form>
|
||||||
|
</main>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
defmodule CMSWeb.Router do
|
defmodule CMSWeb.Router do
|
||||||
use CMSWeb, :router
|
use CMSWeb, :router
|
||||||
|
|
||||||
import CMSWeb.AdminMode
|
import CMSWeb.AdminAuth
|
||||||
|
import CMSWeb.Globals
|
||||||
|
|
||||||
alias CMSWeb.AdminMode
|
alias CMSWeb.AdminAuth
|
||||||
|
alias CMSWeb.Globals
|
||||||
|
|
||||||
pipeline :browser do
|
pipeline :browser do
|
||||||
plug :accepts, ["html"]
|
plug :accepts, ["html"]
|
||||||
|
@ -12,23 +14,37 @@ defmodule CMSWeb.Router do
|
||||||
plug :put_root_layout, html: {CMSWeb.Layouts, :root}
|
plug :put_root_layout, html: {CMSWeb.Layouts, :root}
|
||||||
plug :protect_from_forgery
|
plug :protect_from_forgery
|
||||||
plug :put_secure_browser_headers
|
plug :put_secure_browser_headers
|
||||||
plug :admin_mode
|
plug :assign_globals
|
||||||
end
|
end
|
||||||
|
|
||||||
live_session :default, on_mount: AdminMode do
|
pipeline :supports_admin_action do
|
||||||
|
plug :mount_admin
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline :requires_admin do
|
||||||
|
plug :mount_admin
|
||||||
|
plug :require_admin
|
||||||
|
end
|
||||||
|
|
||||||
|
live_session :default, on_mount: [AdminAuth, Globals] do
|
||||||
scope "/", CMSWeb do
|
scope "/", CMSWeb do
|
||||||
pipe_through :browser
|
pipe_through :browser
|
||||||
|
pipe_through :supports_admin_action
|
||||||
|
|
||||||
get "/", PageController, :home
|
get "/", PageController, :home
|
||||||
get "/writing", PageController, :writing
|
get "/writing", PageController, :writing
|
||||||
get "/microblog", PageController, :microblog
|
get "/microblog", PageController, :microblog
|
||||||
|
|
||||||
live "/admin", AdminLive
|
live "/sign-in", AdminLoginLive
|
||||||
|
post "/admin/session/create", AdminSessionController, :create
|
||||||
|
get "/admin/session/destroy", AdminSessionController, :destroy
|
||||||
|
end
|
||||||
|
|
||||||
live "/admin/sign-in", AdminLoginLive
|
scope "/admin", CMSWeb do
|
||||||
|
pipe_through :browser
|
||||||
|
pipe_through :requires_admin
|
||||||
|
|
||||||
post "/admin/session", AdminSessionController, :create
|
live "/", AdminLive
|
||||||
delete "/admin/session", AdminSessionController, :destroy
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue