Вход пользователя с JSF 2.0

Я пытаюсь - с JSF 2.0 - реализовать аккуратным способом управление логином/записью/выводом. Поскольку традиционный способ <form action="j_security_check" ... не обладает гибкостью, я решил пойти по другому пути, но я нашел проблему.

Декларативная безопасность правильно устанавливается как на сервере приложений через <security-domain>, так и в web.xml через <security-constraint>, <login-config> и <form-login-page>.

Страница входа:

<h:form id="loginForm"> 
    <h:panelGrid columns="2" cellspacing="5">
        <h:outputText value="Username" />
        <h:inputText value="#{loginBean.username}" />
        <h:outputText value="Password:" />
        <h:inputText value="#{loginBean.password}" />
        <h:outputLabel value=""/>
        <h:commandButton value="Login" action="#{loginBean.login}" />
    </h:panelGrid>      
</h:form>

И простой LoginBean # login():

public String login( )
{
    HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance( ).getExternalContext( ).getRequest( );        
    try {
        request.login( username, password );
    }
    catch ( ServletException e ) {
        FacesContext.getCurrentInstance().addMessage( "Unknown login...
        return null;
    }       
    return "i_dont_know_where_you_were_going";
}

Все работает нормально, но после успешного входа я не знаю, как перенаправить пользователя в исходный запрос. Поскольку страница входа автоматически вставлена ​​между запросом клиента и "любым" защищенным ресурсом, мне нужен способ понять, где перенаправить действие. request.getRequestURL( ) не помогает, возможно, из-за RequestDispatcher#forward() (который перезаписывает запрос url). Считаете ли вы, что это подходящий способ управления процессом входа в систему? Если да, то какой-нибудь намек на проблему?

Спасибо большое!

Ответ 1

Добавьте в свою учетную запись что-то вроде следующей строки. Он сохраняет запрашиваемую страницу во время входа в систему.

<f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />

Затем введите запрошенный uri в свой логин bean.

FacesContext context = FacesContext.getCurrentInstance();
String redirect = context.getExternalContext().getRequestParameterMap().get("redirect");

Добавьте ?faces-redirect=true в строку и верните ее.

Ответ 2

Вышеупомянутый ответ работал отлично, просто указывая на неосторожного. f: имя параметра должно быть внутри чего-то вроде commandButton...

<p:commandButton value="Entrar" icon="ui-icon-disk" action="#{userMB.login}" update="avisos,mensagens" ajax="false">
<f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />
</ p: commandButton>

Ответ 3

Кажется, что это работает только при размещении между кнопкой (Mojarra 2.2, Glassfish 4). Вам понадобятся эти два тега <f:param javax.servlet.forward.request_uri и javax.servlet.forward.query_string, чтобы обеспечить точную переадресацию на все типы URL (с или без строк запроса). Убедитесь, что у вас есть что-то похожее на фрагмент ниже на вашей странице входа, то есть на страницу, указанную в вашем web.xml для входа (<form-login-page>/login.xhtml</form-login-page>).

<h:commandButton value="Login" action="#{securityController.login()}">
  <f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />
  <f:param name="query_string" value="#{requestScope['javax.servlet.forward.query_string']}" />
</h:commandButton>

Затем вы можете получить оба параметра в резервной копии bean после отправки формы, как показано ниже

public String login() {
    try {
       String nextPage = "/index.xhtml"; // have a default value in case the user goes to login page directly.
       ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
       Map<String, String> map = ctx.getRequestParameterMap();
       String redirect = map.get("redirect");
       String queryString = map.get("query_string");
       HttpServletRequest request = (HttpServletRequest) ctx.getRequest();
       request.login(this.username, this.password);
       // here login is successful otherwise it would've thrown exception
       // now let check the kind of URL our user was going to 
       if (redirect != null && !redirect.isEmpty()) {  // if redirect is null, return the default page
       // please use faces-redirect = true to ensure URL change in the browser
          if (queryString != null) {
              nextPage = redirect + "?" + queryString + "&faces-redirect=true";
          } else {  // there is no query string, nextPage = redirect
              nextPage = redirect + "&faces-redirect=true";
          }
          // Caveat: You may not need the next lines of code. 
          // I discovered that the `redirect` string has my context path  
          // value in it and so it was'nt redirecting. Remove the context path
          if (nextPage.contains(request.getContextPath())) {
            nextPage = nextPage.substring(request.getContextPath().length());
          }
      }

    } catch (ServletException ex) {
      Logger.getLogger(SecurityController.class.getName()).log(Level.SEVERE, null, ex);
      // invalid username or password
      return "/login.xhtml?failed=true";  // or login error page
    }
 return nextPage;
}

Надеюсь, это поможет кому-то.