2012-11-16 8 views
9

Ho appena iniziato a imparare Java EE. Il mio obiettivo è implementare un portale web (con EJB 3 e JSF) per i giocatori di badminton, in cui gli utenti possono pubblicare e analizzare i loro risultati.Sicurezza Java EE - Non reindirizzato alla pagina iniziale dopo il login

Per semplificare l'operazione (beh, si scopre che in realtà non lo è) Ho deciso di utilizzare il sistema di sicurezza fornito dal contenitore (JBoss as7). Dopo qualche problema sono riuscito a far funzionare l'autenticazione/autorizzazione. Tuttavia, ho un problema che non sono stato in grado di risolvere.

Quando provo ad accedere a una pagina protetta ottengo, come previsto, intercettato dal sistema di sicurezza. Tuttavia, dopo aver effettuato l'accesso non sono reindirizzato alla pagina inizialmente richiesta. Invece mi viene chiesto ancora una volta di accedere. Se digito manualmente l'indirizzo originale, posso accedere alla pagina senza problemi.

Ho letto molti thread su StackOverflow, ma non sono stato in grado di risolvere il mio problema. Sarei davvero grato se qualcuno potesse aiutarmi!

Authentication.java:

@ManagedBean 
@SessionScoped 
public class Authentication { 

    private String username = ""; 
    private String password = ""; 

    private User user = new User(); 

    @EJB 
    UserService service; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public User getUser() { 
     return user; 
    } 

    public void login() { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     HttpServletRequest request = (HttpServletRequest) context 
      .getExternalContext().getRequest(); 

     try { 
      Principal userPrincipal = request.getUserPrincipal(); 
      if (userPrincipal != null) { 
       request.logout(); 
      } 
      request.login(username, password); 
      user = service.find(username, password); 
     } catch (ServletException e) { 
      context.addMessage(null, new FacesMessage("Unknown login")); 
     } 
    } 

    public String logout() { 
     FacesContext.getCurrentInstance().getExternalContext() 
      .invalidateSession(); 
     return "login"; 
    } 
} 

login.xhtml

<h:body> 
    <h:form> 
     <h:outputLabel for="username" value="Username" /> 
     <h:inputText id="username" value="#{authentication.username}" required="true" /> 
     <h:message for="username" /> 
     <br /> 
     <h:outputLabel for="password" value="Password" /> 
     <h:inputSecret id="password" value="#{authentication.password}" required="true" /> 
     <h:message for="password" /> 
     <br /> 
     <h:commandButton value="Login" action="#{authentication.login()}" /> 
     <h:messages globalOnly="true" /> 
    </h:form> 
</h:body> 

home.xhtml

<!DOCTYPE html> 
<html xmlns='http://www.w3.org/1999/xhtml' 
xmlns:f='http://java.sun.com/jsf/core' 
xmlns:h='http://java.sun.com/jsf/html' 
xmlns:ui='http://java.sun.com/jsf/facelets' 
xmlns:p="http://primefaces.org/ui"> 
<h:head> 
    <link type="text/css" rel="stylesheet" 
     href="#{request.contextPath}/themes/cupertino/skin.css" /> 
</h:head> 
<h:body> 
    <h:form> 
     <h:commandButton action="login" value="Log in" /> 
    </h:form> 
</h:body> 

web.xml

.... 
<display-name>BadmintonPortal</display-name> 
<welcome-file-list> 
    <welcome-file>/pages/protected/user/user_home.xhtml</welcome-file> 
</welcome-file-list> 
<servlet> 
    <servlet-name>Faces Servlet</servlet-name> 
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>Faces Servlet</servlet-name> 
    <url-pattern>/faces/*</url-pattern> 
    <url-pattern>*.jsf</url-pattern> 
    <url-pattern>*.xhtml</url-pattern> 
</servlet-mapping> 
<context-param> 
    <param-name>primefaces.THEME</param-name> 
    <param-value>cupertino</param-value> 
</context-param> 

<!-- Protected area definition --> 
<security-constraint> 
    <web-resource-collection> 
     <web-resource-name>Restricted Area - ADMIN Only</web-resource-name> 
     <url-pattern>/pages/protected/admin/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <role-name>admin</role-name> 
    </auth-constraint> 
</security-constraint> 
<security-constraint> 
    <web-resource-collection> 
     <web-resource-name>Restricted Area - USER and ADMIN</web-resource-name> 
     <url-pattern>/pages/protected/user/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <role-name>user</role-name> 
     <role-name>admin</role-name> 
    </auth-constraint> 
</security-constraint> 

<!-- Login page --> 
<login-config> 
    <auth-method>FORM</auth-method> 
    <form-login-config> 
     <form-login-page>/pages/public/login.xhtml</form-login-page> 
     <form-error-page>/pages/public/loginError.xhtml</form-error-page> 
    </form-login-config> 
</login-config> 

<!-- System roles --> 
<security-role> 
    <role-name>admin</role-name> 
</security-role> 
<security-role> 
    <role-name>user</role-name> 
</security-role> 

Edit:

dimenticato di includere faces-config.xml file di

<?xml version="1.0" encoding="UTF-8"?> 

<faces-config xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd" 
    version="2.1"> 

    <navigation-rule> 
     <navigation-case> 
      <from-outcome>login</from-outcome> 
      <to-view-id>/pages/protected/user/user_home.xhtml</to-view-id> 
      <redirect/> 
     </navigation-case> 
    </navigation-rule> 
</faces-config> 

jboss-web.xml

<?xml version='1.0' encoding='UTF-8'?> 

<jboss-web> 
    <context-root>BadmintonPortal</context-root> 
    <security-domain>java:/jaas/BadmintonPortalRealm</security-domain> 
</jboss-web> 

Edit 2:

Soluzione di lavoro

@ManagedBean 
@ViewScoped 
public class Authentication { 
    ... 
    public Authentication() { 
     ExternalContext eContext = FacesContext.getCurrentInstance() 
      .getExternalContext(); 
     uri = (String) eContext.getRequestMap().get(
      RequestDispatcher.FORWARD_REQUEST_URI); 
    } 

    public void login() { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     HttpServletRequest request = (HttpServletRequest) context 
      .getExternalContext().getRequest(); 

     try { 
      Principal userPrincipal = request.getUserPrincipal(); 
      if (userPrincipal != null) { 
       request.logout(); 
      } 
      request.login(username, password); 
      user = service.find(username, password); 
      context.getExternalContext().getSessionMap().put("user", user); 
      context.getExternalContext().redirect(uri); 
     } catch (ServletException e) { 
      context.addMessage(null, new FacesMessage("Unknown login")); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public String logout() { 
     FacesContext.getCurrentInstance().getExternalContext() 
      .invalidateSession(); 
     return "login"; 
    } 
} 
+0

Quale dominio di sicurezza si sta utilizzando (definito in WEB-INF/jboss-web.xml)? Sembra che non ti stia affidando al modello di autenticazione JBoss al 100%. Il modulo di login dovrebbe seguire questo modello: https://community.jboss.org/wiki/SecureAWebApplicationUsingACustomForm. Se segui questo modello non dovresti aver bisogno di implementare alcun bean di autenticazione. – Toni

+0

Ho aggiunto i file faces-config e jboss-web. Per ora li ho mantenuti il ​​più semplice possibile. Il motivo per cui ho implementato il bean di autenticazione era che potevo usare il tag (e quindi essere in grado di usare primefaces). – Toss

+0

È interessante, quindi non stai davvero utilizzando il dominio di sicurezza, giusto? – Toni

risposta

8

Stai prendendo il controllo della parte di accesso utilizzando un modulo che svolge JSF un accesso programmatico in un bean gestito JSF al momento dell'invio. Se si stesse utilizzando un semplice modulo HTML che si invia direttamente all'URL dell'autenticazione gestita dal contenitore j_security_check come descritto nella prima parte di this answer, verrà automaticamente reindirizzato alla pagina iniziale.

Tuttavia, dal momento che si sta effettuando l'accesso con le proprie mani utilizzando JSF personalmente, è inoltre necessario navigare nella pagina iniziale utilizzando JSF.Poiché la pagina di accesso viene generalmente aperta da un lato server avanti di RequestDispatcher#forward(), la pagina richiesta inizialmente è disponibile come attributo di richiesta con il nome specificato nella costante RequestDispatcher.FORWARD_REQUEST_URI. In termini JSF, che è quindi disponibile come segue:

String originalURI = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI); 

(tenere a mente per avere un URL di ripiego per il caso restituisce null, vale a dire quando è stato aperto direttamente senza colpire un URL ristretto prima)

Il luogo migliore per la raccolta sarebbe il costruttore (post) di un bean @ViewScoped associato alla pagina di accesso. Con la sessione corrente ambito approccio di fagioli, probabilmente sarebbe meglio fare una vista ambito uno e durante il login esplicitamente messo il User nello scope di sessione come segue:

externalContext.getSessionMap().put("user", user); 

questo modo l'utente è disponibile per #{user} direttamente invece di #{authentication.user}.

+0

Grazie per il tuo contributo! Io ricevo null dalla RequestMap, quindi non funziona ancora :(. Avete qualche idea? – Toss

+0

Avete cambiato il bean in modo da avere uno scope di vista? State premendo la pagina con restrizioni invece che direttamente la pagina di login – BalusC

+1

Ho funzionato, ho spostato la chiamata su getRequestMap nel costruttore, ora funziona come un fascino Grazie mille BalusC, mi sono tolto i capelli cercando di farlo funzionare! – Toss

Problemi correlati