2012-11-16 93 views
9

我剛開始學習Java EE。我的目標是爲羽毛球運動員實施一個門戶網站(使用EJB 3和JSF),用戶可以在其中發佈和分析他們的結果。Java EE安全性 - 登錄後未重定向到初始頁面

爲了保持簡單(事實證明它確實沒有)我決定使用容器提供的安全系統(JBoss as7)。在遇到一些問題後,我設法使認證/授權起作用。但是,我有一個我無法解決的問題。

當我試圖訪問受保護的頁面時,我收到了安全系統攔截的預期結果。但是,在我登錄後,我不會重定向到最初請求的頁面。相反,我再次被要求登錄。 如果我手動鍵入原始地址,我可以毫無困難地訪問該頁面。

我已經閱讀了stackoverflow上的很多線程,但一直未能解決我的問題。如果有人能幫助我,我會很感激!

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> 

編輯:

忘了包括faces-config.xml中文件

<?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> 

編輯2:

工作液

@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

您正在使用哪個安全域(在WEB-INF/jboss-web.xml中定義)?它看起來像你不依賴於100%的JBoss認證模型。登錄模塊應該遵循以下模型:https://community.jboss.org/wiki/SecureAWebApplicationUsingACustomForm。如果你遵循這個模型,你不需要實現任何認證bean。 – Toni

+0

我添加了faces-config和jboss-web文件。現在我已經儘可能簡單地保持它們。我實現身份驗證bean的原因是,我可以使用標記(從而能夠使用primefaces)。 – Toss

+0

這很有趣,那麼你並沒有真正使用安全域,對吧? – Toni

回答

8

你使用它執行JSF形式接管登錄部分提交時在JSF託管bean中進行程序化登錄。如果您使用的純HTML表單直接提交到this answer的第一部分中概述的容器管理認證URL j_security_check,那麼您確實會自動將其重定向到初始頁面。

但是,由於您自己使用JSF進行自己的登錄,所以您還應該自己使用JSF導航到初始頁面。由於登錄頁面通常由服務器端由RequestDispatcher#forward()轉發,因此最初請求的頁面可用作請求屬性,其名稱如RequestDispatcher.FORWARD_REQUEST_URI中所指定的常量。在JSF而言,這是因此可供如下:

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

(記住有它返回null的情況下,即後備網址時,它已經沒有擊中受限制的URL第一直接打開)

收集它的最佳位置是與登錄頁面關聯的@ViewScoped bean的(後)構造函數。與當前會話範圍的bean的方法,它很可能會更好,使之成爲視圖範圍的一個和登錄過程中明確提出了User在會話範圍如下:

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

這種方式,用戶可通過#{user}直接代替#{authentication.user}

+0

感謝您的輸入! 我從RequestMap中收到null,所以它仍然不起作用:(你有什麼想法嗎? – Toss

+0

你是否已經將bean更改爲一個視圖scoped?您是否直接訪問受限制的頁面而不是直接登錄頁面本身? – BalusC

+1

我得到它的工作。我調用getRequestMap到構造函數。現在它像一個魅力。 非常感謝BalusC,我一直拉着我的頭髮試圖讓它工作! – Toss

相關問題