Skip to content

Commit ecc3790

Browse files
committed
Update phx.gen.auth with sudo mode and magic links
Closes #6041. Still todo: documentation.
1 parent 278cd45 commit ecc3790

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1247
-1951
lines changed

lib/mix/tasks/phx.gen.auth.ex

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -298,34 +298,6 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
298298
"#{singular}_live",
299299
"login_test.exs"
300300
],
301-
"reset_password_live.ex": [
302-
web_pre,
303-
"live",
304-
web_path,
305-
"#{singular}_live",
306-
"reset_password.ex"
307-
],
308-
"reset_password_live_test.exs": [
309-
web_test_pre,
310-
"live",
311-
web_path,
312-
"#{singular}_live",
313-
"reset_password_test.exs"
314-
],
315-
"forgot_password_live.ex": [
316-
web_pre,
317-
"live",
318-
web_path,
319-
"#{singular}_live",
320-
"forgot_password.ex"
321-
],
322-
"forgot_password_live_test.exs": [
323-
web_test_pre,
324-
"live",
325-
web_path,
326-
"#{singular}_live",
327-
"forgot_password_test.exs"
328-
],
329301
"settings_live.ex": [web_pre, "live", web_path, "#{singular}_live", "settings.ex"],
330302
"settings_live_test.exs": [
331303
web_test_pre,
@@ -347,45 +319,13 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
347319
web_path,
348320
"#{singular}_live",
349321
"confirmation_test.exs"
350-
],
351-
"confirmation_instructions_live.ex": [
352-
web_pre,
353-
"live",
354-
web_path,
355-
"#{singular}_live",
356-
"confirmation_instructions.ex"
357-
],
358-
"confirmation_instructions_live_test.exs": [
359-
web_test_pre,
360-
"live",
361-
web_path,
362-
"#{singular}_live",
363-
"confirmation_instructions_test.exs"
364322
]
365323
]
366324

367325
remap_files(default_files ++ live_files)
368326

369327
_ ->
370328
non_live_files = [
371-
"confirmation_html.ex": [controller_pre, "#{singular}_confirmation_html.ex"],
372-
"confirmation_new.html.heex": [
373-
controller_pre,
374-
"#{singular}_confirmation_html",
375-
"new.html.heex"
376-
],
377-
"confirmation_edit.html.heex": [
378-
controller_pre,
379-
"#{singular}_confirmation_html",
380-
"edit.html.heex"
381-
],
382-
"confirmation_controller.ex": [controller_pre, "#{singular}_confirmation_controller.ex"],
383-
"confirmation_controller_test.exs": [
384-
web_test_pre,
385-
"controllers",
386-
web_path,
387-
"#{singular}_confirmation_controller_test.exs"
388-
],
389329
"registration_new.html.heex": [
390330
controller_pre,
391331
"#{singular}_registration_html",
@@ -399,29 +339,9 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
399339
"#{singular}_registration_controller_test.exs"
400340
],
401341
"registration_html.ex": [controller_pre, "#{singular}_registration_html.ex"],
402-
"reset_password_html.ex": [controller_pre, "#{singular}_reset_password_html.ex"],
403-
"reset_password_controller.ex": [
404-
controller_pre,
405-
"#{singular}_reset_password_controller.ex"
406-
],
407-
"reset_password_controller_test.exs": [
408-
web_test_pre,
409-
"controllers",
410-
web_path,
411-
"#{singular}_reset_password_controller_test.exs"
412-
],
413-
"reset_password_edit.html.heex": [
414-
controller_pre,
415-
"#{singular}_reset_password_html",
416-
"edit.html.heex"
417-
],
418-
"reset_password_new.html.heex": [
419-
controller_pre,
420-
"#{singular}_reset_password_html",
421-
"new.html.heex"
422-
],
423342
"session_html.ex": [controller_pre, "#{singular}_session_html.ex"],
424343
"session_new.html.heex": [controller_pre, "#{singular}_session_html", "new.html.heex"],
344+
"session_confirm.html.heex": [controller_pre, "#{singular}_session_html", "confirm.html.heex"],
425345
"settings_html.ex": [web_pre, "controllers", web_path, "#{singular}_settings_html.ex"],
426346
"settings_controller.ex": [controller_pre, "#{singular}_settings_controller.ex"],
427347
"settings_edit.html.heex": [

priv/templates/phx.gen.auth/auth.ex

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,34 @@ defmodule <%= inspect auth_module %> do
2424
so LiveView sessions are identified and automatically
2525
disconnected on log out. The line can be safely removed
2626
if you are not using LiveView.
27+
28+
In case the <%= schema.singular %> re-authenticates for sudo mode,
29+
the existing remember_me setting is kept, writing a new remember_me cookie.
2730
"""
2831
def log_in_<%= schema.singular %>(conn, <%= schema.singular %>, params \\ %{}) do
2932
token = <%= inspect context.alias %>.generate_<%= schema.singular %>_session_token(<%= schema.singular %>)
3033
<%= schema.singular %>_return_to = get_session(conn, :<%= schema.singular %>_return_to)
34+
remember_me = get_session(conn, :<%= schema.singular %>_remember_me)
3135

3236
conn
3337
|> renew_session()
3438
|> put_token_in_session(token)
35-
|> maybe_write_remember_me_cookie(token, params)
39+
|> maybe_write_remember_me_cookie(token, params, remember_me)
3640
|> redirect(to: <%= schema.singular %>_return_to || signed_in_path(conn))
3741
end
3842

39-
defp maybe_write_remember_me_cookie(conn, token, %{"remember_me" => "true"}) do
40-
put_resp_cookie(conn, @remember_me_cookie, token, @remember_me_options)
41-
end
43+
defp maybe_write_remember_me_cookie(conn, token, %{"remember_me" => "true"}, _),
44+
do: write_remember_me_cookie(conn, token)
45+
46+
defp maybe_write_remember_me_cookie(conn, token, _params, true),
47+
do: write_remember_me_cookie(conn, token)
4248

43-
defp maybe_write_remember_me_cookie(conn, _token, _params) do
49+
defp maybe_write_remember_me_cookie(conn, _token, _params, _), do: conn
50+
51+
defp write_remember_me_cookie(conn, token) do
4452
conn
53+
|> put_session(:<%= schema.singular %>_remember_me, true)
54+
|> put_resp_cookie(@remember_me_cookie, token, @remember_me_options)
4555
end
4656

4757
# This function renews the session ID and erases the whole
@@ -124,9 +134,6 @@ defmodule <%= inspect auth_module %> do
124134
on <%= schema.singular %>_token.
125135
Redirects to login page if there's no logged <%= schema.singular %>.
126136
127-
* `:redirect_if_<%= schema.singular %>_is_authenticated` - Authenticates the <%= schema.singular %> from the session.
128-
Redirects to signed_in_path if there's a logged <%= schema.singular %>.
129-
130137
## Examples
131138
132139
Use the `on_mount` lifecycle macro in LiveViews to mount or authenticate
@@ -164,13 +171,18 @@ defmodule <%= inspect auth_module %> do
164171
end
165172
end
166173

167-
def on_mount(:redirect_if_<%= schema.singular %>_is_authenticated, _params, session, socket) do
174+
def on_mount(:ensure_sudo_mode, _params, session, socket) do
168175
socket = mount_current_<%= schema.singular %>(socket, session)
169176

170-
if socket.assigns.current_<%= schema.singular %> do
171-
{:halt, Phoenix.LiveView.redirect(socket, to: signed_in_path(socket))}
172-
else
177+
if <%= inspect context.alias %>.sudo_mode?(socket.assigns.current_<%= schema.singular %>, -10) do
173178
{:cont, socket}
179+
else
180+
socket =
181+
socket
182+
|> Phoenix.LiveView.put_flash(:error, "You must re-authenticate to access this page.")
183+
|> Phoenix.LiveView.redirect(to: ~p"<%= schema.route_prefix %>/log-in")
184+
185+
{:halt, socket}
174186
end
175187
end
176188

@@ -182,7 +194,22 @@ defmodule <%= inspect auth_module %> do
182194
end)
183195
end
184196

185-
<% end %>@doc """
197+
<% else %>@doc """
198+
Used for routes that require sudo mode.
199+
"""
200+
def require_sudo_mode(conn, _opts) do
201+
if <%= inspect context.alias %>.sudo_mode?(conn.assigns.current_<%= schema.singular %>, -10) do
202+
conn
203+
else
204+
conn
205+
|> put_flash(:error, "You must re-authenticate to access this page.")
206+
|> maybe_store_return_to()
207+
|> redirect(to: ~p"<%= schema.route_prefix %>/log-in")
208+
|> halt()
209+
end
210+
end
211+
212+
@doc """
186213
Used for routes that require the <%= schema.singular %> to not be authenticated.
187214
"""
188215
def redirect_if_<%= schema.singular %>_is_authenticated(conn, _opts) do
@@ -195,7 +222,7 @@ defmodule <%= inspect auth_module %> do
195222
end
196223
end
197224

198-
@doc """
225+
<% end %>@doc """
199226
Used for routes that require the <%= schema.singular %> to be authenticated.
200227
201228
If you want to enforce the <%= schema.singular %> email is confirmed before
@@ -213,17 +240,38 @@ defmodule <%= inspect auth_module %> do
213240
end
214241
end
215242

216-
defp put_token_in_session(conn, token) do
243+
<%= if live? do %>defp put_token_in_session(conn, token) do
217244
conn
218245
|> put_session(:<%= schema.singular %>_token, token)
219-
|> put_session(:live_socket_id, "<%= schema.plural %>_sessions:#{Base.url_encode64(token)}")
246+
|> put_session(:live_socket_id, <%= schema.singular %>_session_topic(token))
247+
end
248+
249+
@doc """
250+
Disconnects existing sockets for the given tokens.
251+
"""
252+
def disconnect_sessions(tokens) do
253+
Enum.each(tokens, fn %{token: token} ->
254+
<%= inspect endpoint_module %>.broadcast(<%= schema.singular %>_session_topic(token), "disconnect", %{})
255+
end)
220256
end
221257

222-
defp maybe_store_return_to(%{method: "GET"} = conn) do
258+
defp <%= schema.singular %>_session_topic(token), do: "<%= schema.plural %>_sessions:#{Base.url_encode64(token)}"
259+
260+
<% else %>defp put_token_in_session(conn, token) do
261+
put_session(conn, :<%= schema.singular %>_token, token)
262+
end
263+
264+
<% end %>defp maybe_store_return_to(%{method: "GET"} = conn) do
223265
put_session(conn, :<%= schema.singular %>_return_to, current_path(conn))
224266
end
225267

226268
defp maybe_store_return_to(conn), do: conn
227269

228-
defp signed_in_path(_conn), do: ~p"/"
270+
<%= if live? do %>@doc "Returns the path to redirect to after log in."
271+
# the <%= schema.singular %> was already logged in, redirect to settings
272+
def signed_in_path(%Plug.Conn{assigns: %{current_<%= schema.singular %>: %<%= inspect context.alias %>.<%= inspect schema.alias %>{}}}) do
273+
~p"<%= schema.route_prefix %>/settings"
274+
end
275+
276+
def signed_in_path(_), do: ~p"/"<% else %>defp signed_in_path(_conn), do: ~p"/"<% end %>
229277
end

0 commit comments

Comments
 (0)