Проблема с использованием HttpServletRequest authenticate () в жизненном цикле JSF - PullRequest
1 голос
/ 31 августа 2011

Я пытаюсь использовать аутентификацию HttpServletRequest в управляемом компоненте JSF для реализации детальной аутентификации в зависимости от конкретного запрашиваемого объекта.

Когда я вызываю authenticate в прослушивателе события preRenderView, если аутентификация вызываетперенаправить на страницу входа, исключение.Я не могу вызвать responseComplete после вызова для аутентификации, потому что FacesContext.getCurrentInstance возвращает ноль.Можно ли вообще вызывать authenticate () в JSF или мне нужно использовать ServletFilter?Вход и выход из HttpServletRequest работают в JSF, поэтому я считаю разумным предположить, что аутентификация должна работать.Это ошибка в Mojarra JSF?

Вот мой код:

Страница, на которой зарегистрирован прослушиватель событий:

<ui:composition template="/template.xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:ice="http://www.icesoft.com/icefaces/component">
<ui:param name="pageTitle" value="Text Clustering Home Page"/>
<ui:define name="metadata">
<f:metadata>

   <f:event type="preRenderView" listener="#{permissionBean.preRender}"/>
</f:metadata>
</ui:define>
<ui:define name="body">

      Text Clustering Home Page
      <h:form>
          <h:panelGrid columns="1">
              <ice:outputText rendered="#{loginService.loggedIn}" value="Logged in User: #{loginService.currentUser.username}"/>
              <h:link rendered="#{!loginService.loggedIn}" value="Register" outcome="Register"/>

              <h:commandLink value="Logout" rendered="#{loginService.loggedIn}" action="#{loginService.logout}"/>
              <h:link value="Login" rendered="#{!loginService.loggedIn}" outcome="Login"/>
          </h:panelGrid> 
      </h:form>

Beanкоторый содержит прослушиватель:

@Named
@RequestScoped
public class PermissionBean implements java.io.Serializable {

public void preRender(CompenentSystemEvent event) {
    HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
  HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
  try {

      if (!request.authenticate(response)) {
          System.out.println("After authenticate, context = " +FacesContext.getCurrentInstance());
          if (FacesContext.getCurrentInstance()!=null) {                   
            FacesContext.getCurrentInstance().responseComplete();
          }
       }          

  } catch (Exception e) {  // may throw ServletException or IOException
      System.out.println("EXCEPTION calling authenticate");                
      e.printStackTrace();
  }                
}

}

Вызов authenticate () не вызывает исключение, но если он возвращает false, то FacesContext.getCurrentInstance () также возвращает ноль, и после выхода из метода я получаюэта ошибка:

javax.enterprise.resource.webcontainer.jsf.context|_ThreadID=23;_Thread
Name=Thread-3;|Exception when handling error trying to reset the
response.
java.lang.NullPointerException
at
com.sun.faces.facelets.tag.jsf.core.DeclarativeSystemEventListener.processEvent(EventHandler.java:126    )

Спасибо, Эллен

1 Ответ

1 голос
/ 31 августа 2011

С HttpServletRequest#authenticate() Javadoc :

boolean authenticate(HttpServletResponse response)
                     throws java.io.IOException,
                            ServletException

Используйте механизм входа в контейнер, настроенный для ServletContext, для аутентификации пользователя, выполняющего этот запрос.

Этот метод может изменить и зафиксировать аргумент HttpServletResponse.

(акцент мой)

Реализация контейнера перенаправит ответ на настроенную страницу входа в систему, когда пользователь не прошел аутентификацию. Вероятно, это также привело к уничтожению HttpServletRequest и, таким образом, к текущему экземпляру FacesContext, который полностью исчез.

Лучше всего позволить JSF выполнять проверку присутствия вошедшего в систему пользователя и выполнять перенаправление вместо контейнера. Правда, это требует дублирования местоположения страницы входа в систему на стороне JSF, но я не вижу других способов, которые будут работать в JSF без перемещения задачи в Filter.

public void preRender(CompenentSystemEvent event) {
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();

    if (ec.getUserPrincipal() == null) {
        ec.redirect(ec.getRequestContextPath() + "/login.xhtml");
    }
}

ExternalContext#redirect() уже неявно вызовет FacesContext#responseComplete(), поэтому вам не нужно делать это самостоятельно.

...