0

この質問はここまでのフォローアップです。

ログイン時に、アプリはrequest.login()を使用して認証のためにコンテナーを参照し、ユーザー名、パスワード、ロール、および場所固有のフィールドを含む「ユーザー」Beanを設定する必要があります。コンテナ(WAS 8)に対する承認が成功したら、ユーザーの役割をチェックして、ユーザーがリダイレクトされる適切なウェルカムページを特定する必要があります。私のコンテナは、基本的に3つのLDAPブランチ、データベース、およびフラットファイルをまとめたフェデレーションリポジトリを実装しています。多くの役割があります(今のところ5つ、おそらくもっと後でなります)。

2つのBeanがあります。RequestScopedCredentialsBeanとLoginという名前のSessionScopedBeanです。Loginにはlogin()メソッドが含まれています。ログイン方法に問題があります。

私の問題は、私が使用するときはいつでも:

Principal userPrincipal = request.getUserPrincipal();
request.getUserPrincipal();
if (userPrincipal != null) {
    request.logout();
}
request.login(credentials.getUsername(), credentials.getPassword());
String name = userPrincipal.getName();

前:

Donor donor = loginService.getDonor(credentials.getUsername());
currentUser = new Users();
currentUser.setLocation(donor.getCenter().getCity());
currentUser.setRole("DONOR");
currentUser.setUserId(credentials.getUsername());
currentUser.setFirstName(donor.getFirstName());
currentUser.setLastName(donor.getLastName());
currentUser.setUsername(credentials.getUsername());
currentUser.setName(credentials.getUsername());
return "users?faces-redirect=true";

currentUserUserBeanがセッションに保存されていません。

コードの最初のチャンクを削除したところ、ユーザーBeanの情報がセッションに保存され、後続のユーザーページで表示できることに気付きました。コードの最初のチャンクを1行ずつ再導入し、次のことに気づきました。

if (userPrincipal != null) {
    request.logout();
}

問題を引き起こします。

プログラムによるセキュリティとJSF2.0/CDIを実装するユーザーBeanをどのように格納することになっていますか?私はこれに何週間も費やしました。リダイレクトをキャッチし、userprincipalを取得し、dbまたはldapを呼び出して追加の属性を取得し、適切なページにリダイレクトするフィルターのような、より複雑なものを実装することを想像できます...しかし、物事を単純にしておきたいと思います。これを行う簡単な方法が必要です。

私はもともと、j_security_checkを使用し、web.xmlでFORMを指定してログインしようとしました。ここで、JSF 2.0フォームとログイン方法を使用して、FORMが無視されてBASICが優先されることに気付きました。System.out.println( "getAuthType?.." + request.getAuthType()); ログインメソッド内で「BASIC」を返します。これにより、キャッシュが煩雑になるため、request.logoutが必要になります。そうしないと、request.loginは失敗します。

私は昨夜、ここへのリンクが含まれているこの夜に出くわしました。したがって、userprincipalを取得し、User Beanを設定して、適切なウェルカムページにリダイレクトする方法があるかもしれません。しかし、その2番目のリンクがどれほど古くなっているかはわかりません。また、j_security_checkを、役割に基づいてユーザーをリダイレクトするページを決定するプログラム的な手段と組み合わせて使用​​できない場合もあるようです。

j_security_checkとprogrammaticsecurity/ JSF / CDIのどちらを使用するかについては、ログインBeanまたは独立したユーザーBeanをセッションに格納できる単純なものを理解する必要があります。

これが私の見解からの私のログインフォームです:

<h:form id="loginForm">
    <fieldset>
        <div class="form-row">
            <h:outputLabel for="username" value="User ID"/>
            <h:inputText id="username" value="#{credentials.username}" 
required="true" size="20" />
        </div>
        <div class="form-row">
            <h:outputLabel for="password" value="Password"/>
            <h:inputSecret id="password" type="password" value="#
{credentials.password}" required="true" />
        </div>

        <div class="form-row"> 
            <h:commandButton styleClass="btn btn-warning" value="Sign In" 
type="submit" action="#{login.login}" />
            <a href="#" id="forgot-password">Forgot you password?</a>
        </div>     
    </fieldset>
</h:form>

これが私のログインBeanです(コードは削除され、関連する部分を紹介するために編集されています):

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.security.auth.Subject;
import javax.security.auth.login.CredentialExpiredException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
@SessionScoped
@Named
public class Login implements Serializable {

    private static final long serialVersionUID = 7965455427888195913L;

    @Inject
    private Credentials credentials;

    @PersistenceContext
    private EntityManager userDatabase;

    @Inject
    LoginService loginService;

    private Users currentUser;
    private Service service;
    private String uniqueSecurityName;
    private String l;

    @SuppressWarnings("unchecked")
    public String login() {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
        System.out.println("The login method has been called.");

        try {
        Principal userPrincipal = request.getUserPrincipal();
        request.getUserPrincipal();
        if (userPrincipal != null) {
            request.logout();
        }
        request.login(credentials.getUsername(), credentials.getPassword());
        String name = userPrincipal.getName();

        System.out.println("getRemoteUser?.." + request.getRemoteUser());
        System.out.println("getUserPrincipal?.." + request.getUserPrincipal());
        System.out.println("getAuthType?.." + request.getAuthType());         

        Donor donor = loginService.getDonor(credentials.getUsername());
        currentUser = new Users();
        currentUser.setLocation(donor.getCenter().getCity());
        currentUser.setRole("DONOR");
        currentUser.setUserId(credentials.getUsername());
        currentUser.setFirstName(donor.getFirstName());
        currentUser.setLastName(donor.getLastName());
        currentUser.setUsername(credentials.getUsername());
        currentUser.setName(credentials.getUsername());
        return "users?faces-redirect=true";
        } catch (Exception e) {}

        return null;
    }
    public void logout() {
        currentUser = null;
    }

    public boolean isLoggedIn() {
        return currentUser != null;
    }

    @Produces
    @LoggedIn
    public Users getCurrentUser() {
        return currentUser;
    }
}

これが私の資格情報Beanです:

import java.io.Serializable;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Default;
import javax.inject.Named;

@RequestScoped
@Named
@Default
public class Credentials implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 6976596855571123825L;
    private String username;
    private String password;

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

後続のusers.xhtmlページは次のとおりです(セッション情報を確認するためのテスト目的のみ)。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/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">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
      <title>Login</title>
      <link href="style/main.css" rel="stylesheet" type="text/css"/>
      <ui:insert name="head"/>
    </head>
<body>

  <div id="container">
    <div id="header">

    </div>

    <div id="sidebar">

    </div>

    <div id="content">
      <h1>Current User</h1>
        <h:dataTable value="#{login.currentUser}" var="u">
            <h:column>
                <f:facet name="header">
                 Username
              </f:facet>
                <h:outputText value="#{u.username}" />
            </h:column>
            <h:column>
                <f:facet name="header">
                 Name
              </f:facet>
                <h:outputText value="#{u.name}" />
            </h:column>
            <h:column>
                <f:facet name="header">
                 Password
              </f:facet>
                <h:outputText value="#{u.password}" />
            </h:column>
        </h:dataTable>
    </div>

    <br style="clear:both"/>
  </div>

</body>
</html>

これが私のユーザーBeanです:

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;

@Entity
public class Users {
    @Id
    private String username;
    private String name;
    private String password;
    @Transient
    private String role;
    @Transient
    private String location;
    @Transient
    private String userId;
    @Transient
    private String firstName;
    @Transient
    private String lastName;

    public Users() {
    }

    public String getUsername() {
        return username;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "User (username = " + username + ", name = " + name + ")";
    }
}
4

1 に答える 1

1

あなたの問題はあなたが推測した通りです、

 if (userPrincipal != null) {
            request.logout();
        }

上記の行でセッションを再作成しています。セッションスコープのBeanでセッションを破棄することはお勧めできません。これにより、セッションBeanがCDIによってクリーンアップされます。

アクションメソッドでセッションBeanをクリーンアップするときに、ユーザー名、パスワードを保存する必要があります。

@ApplicationScoped
class LoginService{

public boolean login(String username,String password) {
                String username = credentials.getUsername();
                String password = credentials.getPassword();
                Principal userPrincipal = request.getUserPrincipal();
                request.getUserPrincipal();
                if (userPrincipal != null) {
                    request.logout();
                }
                boolean loggedIn = request.login(username,password);
                if(loggedIn){
                users = new Users();
                users.setUsername(username);  
                session.setAttribute("Users",users);               
                }
              return loggedIn;
    }

}

クレデンシャルにログインするためのアクションメソッドを保持します

  @RequestScoped  
    class Credential {
          @Inject  LoginService loginService;
          String username;
          String password;

          login(ActionEvent action){
           if(loginService.login(username,password))
               //redirect to users
            else
               //show error
          }
    }

CDIからログインしたユーザーを取得するための注釈を作成します

@Retention(RetentionPolicy.RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface SpringBean {
    String value() default "";
}

BeanLocatorクラスを使用してオブジェクトを生成します。このメソッドをLoginServiceに追加できますが、分離しておくことをお勧めします。

    public class BeanLocator {    
    @Produces @LoggedInUser
    public Object getSessionAttribute(InjectionPoint ip){
        String beanName = ip.getAnnotated().
                              getAnnotation(SessionAttribute.class).value();
        if(beanName==null || beanName.equals(""))
            beanName = getDefaultBeanName(ip.getMember().
                               getDeclaringClass().getName());
        return  FacesContext.getCurrentInstance().getExternalContext().
                    getSessionMap().get(beanName);
    }
   } 

次のような他のサービスで使用します

class MyOtherBean{
 @Inject @@LoggedInUser Users;
}
于 2013-03-25T17:34:40.743 に答える