两个根页面;一种用于未经身份验证的用户,一种用于经过身份验证的用户

Two root pages; one for unauthenticated users, one for authenticated users

我想知道如何使用 Phoenix 在同一个根“/”中实现两个页面?一种用于未经身份验证的用户,一种用于经过身份验证的用户。发生这种情况的用例示例是 LinkedIn 和 Facebook,登录页面在“/”上提供,登录后在“/”上提供应用程序。

我使用 Guardian 进行身份验证,并将我的路由器设置为:

 pipeline :auth do
   plug Guardian.Plug.EnsureAuthenticated, handler: App.AuthHandler
  end
 pipeline :unauth do
   plug Guardian.Plug.EnsureNotAuthenticated, handler: App.AuthHandler
 end

 scope "/", App.Web do
   pipe_through [:browser, :unauth]

   get "/", FrontController, :index
 end
 scope "/", App.Web do
   pipe_through [:browser, :auth]

   get "/page", ApplicationController, :index
 end

其中 FrontController 服务于未经身份验证的用户可访问的页面(例如登录页面),而 ApplicationController 服务于实际应用程序。

当 ApplicationController 提供“/”而不是“/page”时,抛出 "this clause cannot match because a previous clause at line 1 always matches" 错误。

我设想使用 if 语句和一个控制器来为两个页面提供服务,不幸的是我找不到关于如何实现这种策略的文档。

很可能,您想要做的是在控制器和视图渲染层处理它,而不是在路由器中。

在您的 "root" 或家庭控制器(任何一个提供“/”作为处理程序的控制器)中,您可以检查您的操作是否具有有效的授权用户,并呈现您的视图想要基于此。

这不是你问的,但在我看来,更好的处理方法是使用两个不同的命名空间,"/" 用于未经身份验证的用户,"/app"(或其他)用于经过身份验证的用户。这使您和您的用户更容易区分两者,并降低系统复杂性。然后,如果未经身份验证的用户试图转到 "/app" 路由,您可以 return 一个 401 Unauthorized 响应(来自您的 App.AuthHandler 内部以及正确的错误消息,例如 "You need to be logged in to do that."

但是如果你坚持按照你写的去做,那么我会在 ApplicationController.index 中简单地处理这种情况 - 不需要 FrontController。该索引操作可能如下所示:

defmodule MyApp.Web.ApplicationController do

  def index(conn, _) do
    case logged_in?(conn) do
      true ->
        user = Guardian.Plug.current_resource(conn)
        render conn, "logged_in_page.html", user: user
      false ->
        render conn, "front_page.html"
    end
  end

  # Note: This could be in a helper module
  defp logged_in?(conn) do
    Guardian.Plug.authenticated?(conn)
  end
end

这样,用户在访问 "/" 时会看到不同的页面,具体取决于他们是否拥有有效的 JWT。

同样,这种方法会使您的系统更加复杂。一般来说,除非你有充分的理由,否则你应该避免复杂性。尽可能遵守约定,您以后会感激不尽。 :)