100 lines
3.3 KiB
Elixir
100 lines
3.3 KiB
Elixir
defmodule Rsh26poolWeb.Auth do
|
|
@moduledoc """
|
|
Token-based authentication.
|
|
|
|
When a user creates or joins a room we generate a random token, persist it on
|
|
their `Participant` row, and store that token in the session cookie. On every
|
|
request the token is looked up to identify the current participant. This is
|
|
the token scheme described in the proposal (a random string whose owner is
|
|
recorded in the database, kept in a cookie).
|
|
"""
|
|
use Rsh26poolWeb, :verified_routes
|
|
|
|
import Plug.Conn
|
|
|
|
alias Phoenix.LiveView
|
|
alias Rsh26pool.Voting
|
|
|
|
@token_key "participant_token"
|
|
|
|
## Plug (controllers) ---------------------------------------------------
|
|
|
|
@doc "Assigns `:current_participant` from the session token (may be nil)."
|
|
def fetch_current_participant(conn, _opts) do
|
|
participant = participant_from_token(get_session(conn, @token_key))
|
|
assign(conn, :current_participant, participant)
|
|
end
|
|
|
|
@doc "Persists a participant's token in the session and assigns it."
|
|
def log_in_participant(conn, participant) do
|
|
conn
|
|
|> put_session(@token_key, participant.token)
|
|
|> assign(:current_participant, participant)
|
|
end
|
|
|
|
@doc "Clears the session token (logout)."
|
|
def log_out_participant(conn) do
|
|
conn
|
|
|> delete_session(@token_key)
|
|
|> assign(:current_participant, nil)
|
|
end
|
|
|
|
## LiveView on_mount hooks ---------------------------------------------
|
|
|
|
@doc """
|
|
`on_mount` hooks:
|
|
|
|
* `:mount_current_participant` — assigns `:current_participant` (may be nil)
|
|
* `:require_participant` — requires the viewer to belong to the room in the
|
|
URL, otherwise redirects to the enter page
|
|
* `:require_owner` — requires the viewer to be the owner of the room
|
|
"""
|
|
def on_mount(:mount_current_participant, _params, session, socket) do
|
|
{:cont, assign_current_participant(socket, session)}
|
|
end
|
|
|
|
def on_mount(:require_participant, params, session, socket) do
|
|
socket = assign_current_participant(socket, session)
|
|
participant = socket.assigns.current_participant
|
|
room_number = params["room_number"]
|
|
|
|
if participant && participant.room && participant.room.room_number == room_number do
|
|
{:cont, socket}
|
|
else
|
|
socket =
|
|
socket
|
|
|> LiveView.put_flash(:error, "このルームに参加するには入室してください。")
|
|
|> LiveView.redirect(to: ~p"/enter?#{[room: room_number]}")
|
|
|
|
{:halt, socket}
|
|
end
|
|
end
|
|
|
|
def on_mount(:require_owner, params, session, socket) do
|
|
socket = assign_current_participant(socket, session)
|
|
participant = socket.assigns.current_participant
|
|
room_number = params["room_number"]
|
|
|
|
if participant && participant.room && participant.room.room_number == room_number &&
|
|
participant.role == "owner" do
|
|
{:cont, socket}
|
|
else
|
|
socket =
|
|
socket
|
|
|> LiveView.put_flash(:error, "この管理ページにアクセスする権限がありません。")
|
|
|> LiveView.redirect(to: ~p"/")
|
|
|
|
{:halt, socket}
|
|
end
|
|
end
|
|
|
|
defp assign_current_participant(socket, session) do
|
|
Phoenix.Component.assign_new(socket, :current_participant, fn ->
|
|
participant_from_token(session[@token_key])
|
|
end)
|
|
end
|
|
|
|
defp participant_from_token(nil), do: nil
|
|
defp participant_from_token(token), do: Voting.get_participant_by_token(token)
|
|
end
|