Две корневые страницы; один для неаутентифицированных пользователей, один для аутентифицированных пользователей

Мне было интересно, как я могу реализовать две страницы в одном корне "/" с помощью 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", "это предложение не может соответствовать, потому что предыдущее предложение в строке 1 всегда совпадает" выдается ошибка.

Я представляю себе использование операторов if и одного контроллера для обслуживания обеих страниц, к сожалению, я не смог найти документацию о том, как реализовать такую ​​стратегию.

2 ответа

Решение

Это не то, что вы спросили, но, по моему скромному мнению, лучший способ справиться с этим - использовать два разных пространства имен, "/" для неаутентифицированных пользователей и "/app" (или что-то) для аутентифицированных пользователей. Это облегчает вам и вашим пользователям различие между ними и снижает сложность системы. Затем, если неаутентифицированные пользователи пытаются перейти к "/app" маршрут вы можете вернуть 401 Unauthorized ответ (изнутри вашего App.AuthHandler вместе с соответствующим сообщением об ошибке, например, "Вы должны войти в систему, чтобы сделать это".

НО, если вы настаиваете на том, чтобы делать то, что вы написали, то я бы просто обработал этот сценарий просто 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.

Опять же, хотя этот подход делает вашу систему более сложной. И вообще говоря, вы должны избегать сложности, если у вас нет действительно веской причины. Следуйте соглашениям, когда это возможно, и вы будете благодарны позже.:)

Скорее всего, что вы хотите сделать, это обработать это на уровне рендера контроллера и представления, а не в маршрутизаторе.

Внутри вашего "корневого" или домашнего контроллера (независимо от того, какой из них служит "/" в качестве обработчика) вы можете проверить в своем действии, есть ли у вас действительный пользователь auth'd или нет, и визуализировать желаемое представление на основе этого.

Другие вопросы по тегам