Как Seam 3 обрабатывает функцию "перенаправить на захват" после входа в систему?
Вот мои варианты использования.
У меня есть страница входа, которая /public/login.xhtml
, Все остальные мои страницы должны войти в систему, прежде чем их достичь. Они в /pages/
каталог.
Я хочу чтобы:
- Если мой пользователь имеет доступ к
http://host/myapp/pages/*
сначала он перенаправляет его на страницу входа, а затем - на URL, который он впервые ввел. - Если мой пользователь имеет доступ к
http://host/myapp/
, он перенаправляет его сначала на страницу входа, а затем, чтобы/pages/home.xhtml
, - Если мой пользователь имеет доступ к
http://host/myapp/public/login.xhtml
, он перенаправляет его сначала на страницу входа, а затем, чтобы/pages/home.xhtml
, - Если мой пользователь имеет доступ к
http://host/myapp/public/login.xhtml
и уже вошел в систему, он перенаправляет на/pages/home.xhtml
,
Что работает в данный момент?
С Seam 3 (v3.1.0.Final) и модулем Security + Faces мой сценарий использования № 1 автоматически работает с:
@ViewConfig
public interface PagesConfig {
static enum Pages {
@ViewPattern("/pages/*")
@LoginView("/public/login.xhtml")
@LoggedIn
LOGGED_IN_PAGES,
}
}
Моя проблема в том, что я не понимаю, как Seam работает над перенаправлением в "представление захвата".
С Seam 2 это было легко понять, в components.xml
мы имеем
<event type="org.jboss.seam.security.notLoggedIn">
<action execute="#{redirect.captureCurrentView}" />
</event>
<event type="org.jboss.seam.security.loginSuccessful">
<action execute="#{redirect.returnToCapturedView}" />
</event>
Таким образом, мы захватили события notLoggedIn
а также loginSuccessful
справиться с этим с redirect
составная часть.
В Seam 3 я не нашел эту конфигурацию: кажется, ничего @Observes LoggedInEvent
и нет Redirect
учебный класс...
Точка № 2 достигается с этим /index.htm
файл:
<html><head>
<meta http-equiv="Refresh" content="0; URL=pages/home.xhtml">
</head></html>
Но для моей точки № 3 я пробовал решения, которые не работают полностью.
Сначала я попробовал это в login.xhtml
:
<f:metadata>
<s:viewAction action="#{loginAction.redirectToHome}" if="#{identity.loggedIn}" immediate="true" />
</f:metadata>
И с или без onPostback="true"
после входа в систему я все еще на странице входа с таким сообщением об ошибке (дважды): "Невозможно найти соответствующий случай навигации с from-view-id" /public/login.xhtml "для действия" # # identity.login } "С результатом" успех "." Это только если я теперь снова получить доступ к http://host/myapp/public/login.xhtml
Это мое viewAction
перенаправляет меня в дом.
Я также попробовал это правило навигации в faces-config.xml
:
<navigation-rule>
<from-view-id>/public/login.xhtml</from-view-id>
<navigation-case>
<if>#{identity.loggedIn}</if>
<to-view-id>/pages/home.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Но тогда мой вариант использования № 1 был отключен: каждый раз, когда я входил в систему, меня перенаправляли в дом.
Наконец, для моей точки № 4, s:viewAction
делает работу
Так кто-нибудь знает лучшие практики для того, чтобы правильно обрабатывать эти 4 варианта использования (которые я считаю наиболее распространенными вариантами использования), особенно пункт № 3?
2 ответа
Наконец вот что я сделал.
<f:metadata>
<s:viewAction action="#{loginAction.redirectToHome}" immediate="true" />
</f:metadata>
Поэтому я удалил if="#{identity.loggedIn}"
чтобы позвонить моему redirectToHome
метод, который перенаправляет на /pages/home.xhtml
,
- Если пользователь уже аутентифицирован, то он перенаправляется на домашнюю страницу.
- Если он не, то он перенаправлен на домашнюю страницу, которая перенаправляет его на страницу входа в систему благодаря моей
@ViewConfig
Здесь loginAction
:
public void redirectToHome() throws IOException {
externalContext.redirect(externalContext.encodeActionURL(externalContext.getRequestContextPath()+"/pages/home.xhtml"));
}
Проблема, с которой я столкнулся, была, когда я вышел из системы.
Вот мое действие выхода из системы:
<h:commandLink action="/public/login" actionListener="#{securityAction.logout()}" value="Disconnect" immediate="true" />
И securityAction.logout()
метод:
public void logout() {
identity.logout();
if (!conversation.isTransient()) {
conversation.end();
}
}
Проблема в том, что я был перенаправлен на страницу входа (спасибо @ViewConfig, я думаю), но нет PreLoginEvent
были брошены, поэтому шов LoginListener.observePreLoginEvent
не был вызван, и поэтому мой предыдущий URL не был помещен в сессию. Поэтому, когда я вошел в систему (сразу после выхода из системы), я застрял на странице входа в систему, но вошел в систему.
Благодаря Brian Leathem и его предыдущему ответу, вот что я сделал: в моем authenticate
метод моего BaseAuthenticator
Я вызвал этот метод после аутентификации:
private void overrideRedirectToLogin() {
final String PRE_LOGIN_URL = LoginListener.class.getName() + "_PRE_LOGIN_URL";
final ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
final Map<String, Object> sessionMap = externalContext.getSessionMap();
String redirectURL = (String) sessionMap.get(PRE_LOGIN_URL);
if (redirectURL == null) {
final HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
redirectURL = request.getRequestURL().toString();
}
sessionMap.put(PRE_LOGIN_URL, redirectURL.replace("/public/login.xhtml", "/pages/home.xhtml"));
}
При таком решении мой предыдущий URL не был установлен в сеансе, но, по крайней мере, мой пользователь перенаправлен на домашнюю страницу.
Вариант использования № - 1 SeamFaces сохраняет первоначально запрошенный viewId в пользовательском сеансе, а затем повторно перенаправляет в это представление после успешного входа в систему. Это делается путем перехвата навигации от кнопки входа в Seam Security и запускает PostLoginEvent с данными, хранящимися в SessionMap.
Вариант использования № 2 - отличное решение с редиректом! Вы также можете сделать это с помощью @UrlMapping в вашем ViewConfig.
Вариант использования № 3. Ваше решение viewAction должно работать, но я полагаю, что вы столкнулись с SEAMFACES-179. Есть несколько решений, которые вы можете использовать:
1) В вашем методе входа в систему вы можете управлять картой видимости, хранящейся на лицах шва, как показано в этом разделе - (это решение любезно предоставлено Коди Лерумом)
2) Используйте PrettyFaces, чтобы перехватить запрос на просмотр входа в систему и перенаправить вас, если вы не вошли в систему.