Hello,
I am working on a web app with Phoenix + Liveview.
I have an authenticated live_session in my router.ex
live_session :dashboard,
on_mount: [MyappWeb.RouteInfo, MyappWeb.UserLiveAuth, MyappWeb.LiveAdminSidebar] do
scope "/dashboard", MyappWeb do
pipe_through [:browser, :require_authenticated_user]
live "/", WelcomeLive.Index, :index
scope "/settings", SettingsLive do
live "/account", Account, :edit
live "/account/confirm_email/:token", Account, :confirm_email
end
scope "/users", UserLive do
live "/", Index, :index
live "/new", Index, :new
live "/:id/edit", Index, :edit
live "/:id", Show, :show
live "/:id/show/edit", Show, :edit
end
scope "/roles", RoleLive do
live "/", Index, :index
live "/new", Index, :new
live "/:id/edit", Index, :edit
live "/:id", Show, :show
live "/:id/show/edit", Show, :edit
end
end
end
I use the on_mount
to handle authentication and authorization as described in this doc page: Security considerations of the LiveView model
Here is my UserLiveAuth on_mount function
def on_mount(:default, _params, %{"user_token" => user_token} = _session, socket) do
socket = socket
|> assign_new(:current_user, fn -> Accounts.get_user_by_session_token(user_token) end)
|> assign_new(:user_return_to, fn -> &Routes.welcome_index_path(&1, :index) end)
|> assign_current_user_access_for_routes()
cond do
!is_user_logged_in(socket) ->
{
:halt,
socket
|> put_flash(:error, "You must log in to access this page.")
|> redirect(to: Routes.user_session_path(socket, :new))
}
!does_user_have_required_capability_for_current_view(socket) ->
{
:halt,
socket
|> put_flash(:error, "Your current role does not allow you to access this page.")
|> push_redirect(to: socket.assigns.user_return_to.(socket))
}
true ->
{
:cont,
assign(socket, :user_return_to, socket.assigns.current_route_info.menu_item.path)
}
end
end
Here is what I’m trying to achieve.
When the authenticated user tries to go to a page he is not allowed to visit (2nd cond), I want to redirect him to the :user_return_to
which would be the last valid page he was on.
So I tried to store the current page on the :cont case (3rd cond), but I realised that the assigns are not persisted after a live_redirect
.
Is it a normal behaviour?
If so, I am not sure of the purpose of assign_new
over assign
.
Here is what is explained in the security considerations of the LiveView model
[assign_new] is a convenience to avoid fetching the
current_user
multiple times across LiveViews
In my case current_user
is fetched everytime I navigate to a new LiveView of the same live session (using live_redirect
links).
Is assign_new
only useful when the socket connection is established?
How could I do to store the :user_return_to
across different LiveViews? Use localStorage?
Thanks in advance for your help.