0

私は、主に と から新たに生成された Web アプリであるプロジェクトで作業していphx.newますphx.gen.auth。ライブビューではないインデックス ページがあります。ログイン後、ユーザーはライブビューであるメイン ページにリダイレクトされます。

期待:生成されたLog outリンクをクリックした後、ユーザーは/、ライブビューではないインデックス ページにリダイレクトされる必要があります。この動作は、生成された認証によって指定されます。

経験:問題は、生成されたLog outリンクをクリックすると、生成された認証が行うように書かれているように、ログアウトしたインデックス スプラッシュ ページにリダイレクトされるのではなく、代わりにログイン ページにリダイレクトされ、そこで 2 つのフラッシュが表示されることです。メッセージ::infoログアウトの成功を示す 1 回のフラッシュと、:error「このページにアクセスするにはログインする必要があります」という不平を言う 2 回目のフラッシュ。:errorログイン ページでそのフラッシュをユーザーに見せたくありません。さらに悪いことに、事実は:errorフラッシュが表示される理由PageLiveは、インデックス ページに存在しないライブビューがそのmount/3機能を再度 (3 回目) 実行しているためであり、これによりライブビュー認証が再度実行され、2 回目のリダイレクトが発生します。この問題が発生しますつまり、リダイレクトが正しく機能し、問題なくユーザーをインデックス ページに送信する場合もあれば、2 回目の冗長なリダイレクトと誤ったフラッシュ メッセージが表示される場合もあります。これはある種の競合状態を示していると思います。

これらのルートを使用して比較的新しく生成されたプロジェクトがあります(特に):

router.ex

  scope "/", MyappWeb do
    pipe_through :browser

    live_session :default do
      live "/dash", PageLive, :index
    end
  end

  scope "/", MyappWeb do
    pipe_through [:browser, :redirect_if_user_is_authenticated]

    get "/", PageController, :index
  end

  scope "/", MyappWeb do
    pipe_through [:browser]

    delete "/users/log_out", UserSessionController, :delete
  end

認証は によって生成されましたphx.gen.auth。生成されたdeleteアクションは、生成されたをUserSessionController起動させますUserAuth.log_out_user/1

user_session_controller.ex

  def delete(conn, _params) do
    conn
    |> put_flash(:info, "Logged out successfully.")
    |> UserAuth.log_out_user()
  end

user_auth.ex

  def log_out_user(conn) do
    user_token = get_session(conn, :user_token)
    user_token && Accounts.delete_session_token(user_token)

    if live_socket_id = get_session(conn, :live_socket_id) do
      MyappWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
    end

    conn
    |> renew_session()
    |> delete_resp_cookie(@remember_me_cookie)
    |> redirect(to: "/")
  end

liveview docsで推奨されているように、ルーター内/dashの liveview と呼ばれる liveview を介してルーティングします。PageLive

page_live.ex

defmodule MyappWeb.PageLive do
  use MyappWeb, :live_view
  alias MyappWeb.Live.Components.PackageSearch
  alias MyappWeb.Live.Components.Tabs
  alias MyappWeb.Live.Components.Tabs.TabItem
  on_mount MyappWeb.UserLiveAuth
end

user_live_auth.ex

defmodule MyappWeb.UserLiveAuth do
  import Phoenix.LiveView, only: [assign_new: 3, redirect: 2]
  alias Myapp.Accounts
  alias Myapp.Accounts.User
  alias MyappWeb.Router.Helpers, as: Routes

  def mount(_params, session, socket) do
    socket =
      assign_new(socket, :current_user, fn ->
        find_current_user(session)
      end)

    case socket.assigns.current_user do
      %User{} ->
        {:cont, socket}

      _ ->
        socket =
          socket
          |> put_flash(:error, "You must be logged in to access this page.")
          |> redirect(to: Routes.user_session_path(socket, :new))

        {:halt, socket}
    end
  end

  defp find_current_user(session) do
    with user_token when not is_nil(user_token) <- session["user_token"],
         %User{} = user <- Accounts.get_user_by_session_token(user_token),
         do: user
  end
end

ユーザーがログアウトをクリックした後のプロセスのログは次のとおりです。

**[info] POST /users/log_out**
[debug] Processing with MyappWeb.UserSessionController.delete/2
  Parameters: %{"_csrf_token" => "ET8xMSU5KSEedycKEAcJfX0JCl45LmcF_VEHANhinNqHcaz6MFRkIqWu", "_method" => "delete"}
  Pipelines: [:browser]
[debug] QUERY OK source="users_tokens" db=1.8ms idle=389.7ms
SELECT u1."id", u1."email", u1."hashed_password", u1."confirmed_at", u1."first_name", u1."last_name", u1."username", u1."inserted_at", u1."updated_at" FROM "users_tokens" AS u0 INNER JOIN "users" AS u1 ON u1."id" = u0."user_id" WHERE ((u0."token" = $1) AND (u0."context" = $2)) AND (u0."inserted_at" > $3::timestamp + (-(60)::numeric * interval '1 day')) [<<159, 144, 113, 83, 223, 12, 183, 119, 50, 248, 83, 234, 128, 237, 129, 112, 138, 147, 148, 100, 67, 163, 50, 244, 127, 26, 254, 184, 102, 74, 11, 52>>, "session", ~U[2021-10-06 22:13:44.080128Z]]
[debug] QUERY OK source="users_tokens" db=1.7ms idle=391.8ms
DELETE FROM "users_tokens" AS u0 WHERE ((u0."token" = $1) AND (u0."context" = $2)) [<<159, 144, 113, 83, 223, 12, 183, 119, 50, 248, 83, 234, 128, 237, 129, 112, 138, 147, 148, 100, 67, 163, 50, 244, 127, 26, 254, 184, 102, 74, 11, 52>>, "session"]
**[info] Sent 302 in 6ms**
**[info] CONNECTED TO Phoenix.LiveView.Socket in 64µs
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" =>** "ET8xMSU5KSEedycKEAcJfX0JCl45LmcF_VEHANhinNqHcaz6MFRkIqWu", "_mounts" => "0", "_track_static" => %{"0" => "http://localhost:4000/assets/app.css", "1" => "http://localhost:4000/assets/app.js"}, "vsn" => "2.0.0"}
[debug] QUERY OK source="users_tokens" db=1.6ms idle=422.5ms
SELECT u1."id", u1."email", u1."hashed_password", u1."confirmed_at", u1."first_name", u1."last_name", u1."username", u1."inserted_at", u1."updated_at" FROM "users_tokens" AS u0 INNER JOIN "users" AS u1 ON u1."id" = u0."user_id" WHERE ((u0."token" = $1) AND (u0."context" = $2)) AND (u0."inserted_at" > $3::timestamp + (-(60)::numeric * interval '1 day')) [<<159, 144, 113, 83, 223, 12, 183, 119, 50, 248, 83, 234, 128, 237, 129, 112, 138, 147, 148, 100, 67, 163, 50, 244, 127, 26, 254, 184, 102, 74, 11, 52>>, "session", ~U[2021-10-06 22:13:44.110158Z]]
**[info] GET /users/log_in**
[debug] Processing with MyappWeb.UserSessionController.new/2
  Parameters: %{}
  Pipelines: [:browser, :redirect_if_user_is_authenticated]
[info] Sent 200 in 6ms

上記のログで、302 リダイレクトが発生し、すぐにソケットが再接続してmount/3実行され、今度は/users/log_inルートへの別のリダイレクトがトリガーされることに注目してください。私が理解している限り、ソケットはここで再接続を試みるべきではなく、何がこれを引き起こしているのかわかりません。

PageLiveログアウト時に非ライブビュー ページへの 302 リダイレクトの後に再度マウントがトリガーされ、ログイン ページへの 2 回目のリダイレクトがトリガーされるのはなぜですか?

4

2 に答える 2