10

Java EEの学習を始めたばかりです。私の目標は、バドミントン プレーヤー用の Web ポータル (EJB 3 と JSF を使用) を実装することです。ここで、ユーザーは自分の結果を投稿して分析できます。

シンプルにするために (実はそうではないことがわかりました)、コンテナーが提供するセキュリティ システム (JBoss as7) を使用することにしました。いくつかの問題の後、認証/承認を機能させることができました。ただし、解決できていない問題が 1 つあります。

保護されたページにアクセスしようとすると、予想どおり、セキュリティ システムによって傍受されます。ただし、ログインした後、最初に要求したページにリダイレクトされません。代わりに、もう一度ログインを求められます。元のアドレスを手動で入力すると、問題なくページにアクセスできます。

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";
    }
}
4

1 に答える 1

8

送信時に JSF マネージド Bean でプログラムによるログインを実行する JSF フォームを使用して、ログイン部分を引き継いでいます。この回答j_security_checkの最初の部分で概説したように、コンテナ管理の認証 URL に直接送信するプレーンな HTML フォームを使用していた場合、実際には自動的に最初のページにリダイレクトされます。

ただし、JSF を使用して自分でログインを取得しているため、JSF を使用して最初のページに移動する必要があります。通常、ログイン ページは によってサーバー側の転送によって開かれるため、最初に要求されたページは、定数RequestDispatcher#forward()で指定された名前の要求属性として使用できます。RequestDispatcher.FORWARD_REQUEST_URIJSF 用語では、次のように使用できます。

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

null(つまり、最初に制限された URL にアクセスせずに直接開いた場合に備えて、フォールバック URL があることに注意してください)

収集するのに最適な場所は@ViewScoped、ログイン ページに関連付けられた Bean の (ポスト) コンストラクターです。User現在のセッション スコープ Bean アプローチでは、ビュー スコープを作成し、ログイン時に次のようにセッション スコープに明示的に配置することをお勧めします。

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

このようにして、ユーザーは#{user}の代わりに直接利用できます#{authentication.user}

于 2012-11-16T17:57:35.647 に答える