Add a way to force user logout

The idea is to remove the session and also disconnect all liveviews
This commit is contained in:
Joao Gilberto Balsini Moura 2020-09-28 06:06:15 -03:00
parent 2564b1b727
commit b6524131c1
6 changed files with 49 additions and 0 deletions

View file

@ -6,6 +6,7 @@ defmodule RealEstate.Accounts do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias RealEstate.Repo alias RealEstate.Repo
alias RealEstate.Accounts.{User, UserToken, UserNotifier} alias RealEstate.Accounts.{User, UserToken, UserNotifier}
alias RealEstateWeb.UserAuth
## Database getters ## Database getters
@ -97,6 +98,21 @@ defmodule RealEstate.Accounts do
|> Repo.insert() |> Repo.insert()
end end
def logout_user(%User{} = user) do
# Delete all user tokens
Repo.delete_all(UserToken.user_and_contexts_query(user, :all))
# Broadcast to all liveviews to immediately disconnect the user
RealEstateWeb.Endpoint.broadcast_from(
self(),
UserAuth.pubsub_topic(),
"logout_user",
%{
user: user
}
)
end
@doc """ @doc """
Returns an `%Ecto.Changeset{}` for tracking user changes. Returns an `%Ecto.Changeset{}` for tracking user changes.

View file

@ -49,6 +49,19 @@ defmodule RealEstateWeb do
unquote(view_helpers()) unquote(view_helpers())
import RealEstateWeb.LiveHelpers import RealEstateWeb.LiveHelpers
alias RealEstate.Accounts.User
@impl true
def handle_info(%{event: "logout_user", payload: %{user: %User{id: id}}}, socket) do
with %User{id: ^id} <- socket.assigns.current_user do
{:noreply,
socket
|> redirect(to: Routes.user_session_path(socket, :force_logout))}
else
_any -> {:noreply, socket}
end
end
end end
end end

View file

@ -5,6 +5,8 @@ defmodule RealEstateWeb.UserAuth do
alias RealEstate.Accounts alias RealEstate.Accounts
alias RealEstateWeb.Router.Helpers, as: Routes alias RealEstateWeb.Router.Helpers, as: Routes
@pubsub_topic "user_updates"
# Make the remember me cookie valid for 60 days. # Make the remember me cookie valid for 60 days.
# If you want bump or reduce this value, also change # If you want bump or reduce this value, also change
# the token expiry itself in UserToken. # the token expiry itself in UserToken.
@ -139,6 +141,11 @@ defmodule RealEstateWeb.UserAuth do
end end
end end
@doc """
Returns the pubsub topic name for receiving notifications when a user updated
"""
def pubsub_topic, do: @pubsub_topic
defp maybe_store_return_to(%{method: "GET"} = conn) do defp maybe_store_return_to(%{method: "GET"} = conn) do
%{request_path: request_path, query_string: query_string} = conn %{request_path: request_path, query_string: query_string} = conn
return_to = if query_string == "", do: request_path, else: request_path <> "?" <> query_string return_to = if query_string == "", do: request_path, else: request_path <> "?" <> query_string

View file

@ -23,4 +23,13 @@ defmodule RealEstateWeb.UserSessionController do
|> put_flash(:info, "Logged out successfully.") |> put_flash(:info, "Logged out successfully.")
|> UserAuth.log_out_user() |> UserAuth.log_out_user()
end end
def force_logout(conn, _params) do
conn
|> put_flash(
:info,
"You were logged out. Please login again to continue using our application."
)
|> UserAuth.log_out_user()
end
end end

View file

@ -3,6 +3,7 @@ defmodule RealEstateWeb.LiveHelpers do
alias RealEstate.Accounts alias RealEstate.Accounts
alias RealEstate.Accounts.User alias RealEstate.Accounts.User
alias RealEstateWeb.Router.Helpers, as: Routes alias RealEstateWeb.Router.Helpers, as: Routes
alias RealEstateWeb.UserAuth
import Phoenix.LiveView.Helpers import Phoenix.LiveView.Helpers
@doc """ @doc """
@ -26,6 +27,8 @@ defmodule RealEstateWeb.LiveHelpers do
end end
def assign_defaults(session, socket) do def assign_defaults(session, socket) do
RealEstateWeb.Endpoint.subscribe(UserAuth.pubsub_topic())
socket = socket =
assign_new(socket, :current_user, fn -> assign_new(socket, :current_user, fn ->
find_current_user(session) find_current_user(session)

View file

@ -76,6 +76,7 @@ defmodule RealEstateWeb.Router do
scope "/", RealEstateWeb do scope "/", RealEstateWeb do
pipe_through [:browser] pipe_through [:browser]
get "/users/force_logout", UserSessionController, :force_logout
delete "/users/log_out", UserSessionController, :delete delete "/users/log_out", UserSessionController, :delete
get "/users/confirm", UserConfirmationController, :new get "/users/confirm", UserConfirmationController, :new
post "/users/confirm", UserConfirmationController, :create post "/users/confirm", UserConfirmationController, :create