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