2011-10-05 67 views
3

我對Java EE相當陌生,剛開始使用我想創建的應用程序時遇到了很多麻煩。我想要的是一個連接到EJB項目的Swing應用程序客戶端。我正在使用Glassfish v3.1.1。到目前爲止,我所擁有的是兩個無狀態bean,其中一個使用Glassfish中的@DeclareRoles和JDBC領域進行保護,並且是客戶端的開始。Java EE 6應用程序客戶端登錄

當客戶端運行時,您可以選擇一個用戶名,輸入密碼,然後登錄。如果您使用正確的密碼,則一切正常(客戶端控制檯吐露一些「安全」信息)。但是,如果您輸入的密碼不正確,則永久鎖定。 InitialContext.lookup不會再次調用CallbackHandler來檢查新密碼,它會繼續使用不正確的憑據。

有人可以告訴我如何正確地做到這一點?我是否對這種情況使用了正確的方法 - 網上有大量的信息,但基本上只有0個例子是我正在嘗試做的事情?一切似乎只適用於J2EE或Servlets!這裏有一些相關的代碼。

與GlassFish ejb-jar.xml中:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 EJB 3.1//EN" "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd"> 
<glassfish-ejb-jar> 
    <security-role-mapping> 
    <role-name>Admin</role-name> 
    <group-name>Admin</group-name> 
    </security-role-mapping> 
    <security-role-mapping> 
    <role-name>Employee</role-name> 
    <group-name>Employee</group-name> 
    </security-role-mapping> 
    <enterprise-beans> 
    <ejb> 
     <ejb-name>LoginBean</ejb-name> 
     <jndi-name>ejb/machineryhub/LoginService</jndi-name> 
    </ejb> 
    <ejb> 
     <ejb-name>EmployeeBean</ejb-name> 
     <jndi-name>ejb/machineryhub/EmployeeService</jndi-name> 
     <ior-security-config> 
     <as-context> 
      <auth_method>username_password</auth_method> 
      <realm>machineryhub</realm> 
      <required>true</required> 
     </as-context> 
     </ior-security-config> 
    </ejb> 
    </enterprise-beans> 
</glassfish-ejb-jar> 

我需要將<ior-security-config>塊添加到每個受保護的bean創建?

應用client.xml的:

<?xml version="1.0" encoding="UTF-8"?> 
<application-client version="6" 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/application-client_6.xsd"> 
    <display-name>MachineryHub</display-name> 
    <ejb-ref> 
    <ejb-ref-name>LoginBean</ejb-ref-name> 
    <ejb-ref-type>Session</ejb-ref-type> 
    <remote>machineryhub.service.LoginService</remote> 
    </ejb-ref> 
    <ejb-ref> 
    <ejb-ref-name>EmployeeBean</ejb-ref-name> 
    <ejb-ref-type>Session</ejb-ref-type> 
    <remote>machineryhub.service.EmployeeService</remote> 
    </ejb-ref> 
    <callback-handler>machineryhub.LoginCallbackHandler</callback-handler> 
</application-client> 

machineryhub.LoginCallbackHandler:

public class LoginCallbackHandler implements CallbackHandler { 

    @Override 
    public void handle(Callback[] clbcks) throws IOException, UnsupportedCallbackException { 
    LoginFrame l = LoginFrame.instance; 
    for (Callback cb : clbcks) { 
     if (cb instanceof NameCallback) { 
     NameCallback ncb = (NameCallback) cb; 
     ncb.setName(l.usernameCombo.getSelectedItem().toString()); 
     } else if (cb instanceof PasswordCallback) { 
     PasswordCallback pcb = (PasswordCallback) cb; 
     pcb.setPassword(l.passwordText.getPassword()); 
     } else { 
     throw new UnsupportedCallbackException(cb); 
     } 
    } 
    } 
} 

現在對於漫長的,Swing應用程序客戶端。

machineryhub.LoginFrame

public class LoginFrame extends JFrame implements ActionListener { 

    public static LoginFrame instance; 

    public static void main(String[] args) { 
    // Handle uncaught exceptions in the main and Swing threads 
    ExceptionHandler.registerExceptionHandler(); 

    SwingUtilities.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
     try { 
      UIManager.setLookAndFeel(new SubstanceMistSilverLookAndFeel()); 
      JFrame.setDefaultLookAndFeelDecorated(true); 
      JDialog.setDefaultLookAndFeelDecorated(true); 
      (new LoginFrame()).setVisible(true); 
     } catch (final Exception exception) { 
      ExceptionHandler.handle(Thread.currentThread(), exception); 
     } 
     } 
    }); 
    } 
    public JComboBox usernameCombo; 
    public JPasswordField passwordText; 
    private JButton loginButton; 

    public LoginFrame() { 
    // Window Setup 

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    this.setTitle("Login :: MachineryHub"); 
    this.setLocationRelativeTo(null); 
    this.setIconImages(IconFactory.application_images); 

    // Create GUI 

    createGui(); 
    usernameCombo.requestFocusInWindow(); 
    LoginFrame.instance = this; 
    } 

    private void createGui() { 
    // Content Pane 
    final JPanel contentPanel = new JPanel(); 

    List<String> usernames = getLoginService().getUsernames(); 
    Collections.sort(usernames); 
    usernameCombo = new JComboBox(usernames.toArray()); 
    passwordText = new JPasswordField(15); 
    passwordText.setActionCommand("Login"); 
    passwordText.addActionListener(this); 

    loginButton = new JButton("Login", IconFactory.getImageIcon(IconFactory.Icon.KEY, 16)); 
    loginButton.setActionCommand("Login"); 
    loginButton.addActionListener(this); 

    GroupLayout layout = new GroupLayout(contentPanel); 
    contentPanel.setLayout(layout); 
    layout.setAutoCreateContainerGaps(true); 
    layout.setAutoCreateGaps(true); 

    layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(usernameCombo).addGroup(layout.createSequentialGroup().addComponent(passwordText).addComponent(loginButton))); 

    layout.setVerticalGroup(layout.createSequentialGroup().addComponent(usernameCombo, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE).addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE).addComponent(passwordText).addComponent(loginButton))); 

    this.setContentPane(contentPanel); 
    this.pack(); 
    } 

    @Override 
    public void actionPerformed(final ActionEvent e) { 
    if (e == null || e.getActionCommand() == null) { 
     return; 
    } 

    if (e.getActionCommand().equals("Login")) { 
     loginButton.setEnabled(false); 
     passwordText.setEnabled(false); 
     usernameCombo.setEnabled(false); 
     loginButton.setIcon(IconFactory.getImageIcon(IconFactory.SpecialImage.LOADING)); 

     try { 
     Context c = new InitialContext(); 

     EmployeeService es = (EmployeeService) c.lookup("ejb/machineryhub/EmployeeService"); 
     System.out.println("Number of employees: " + es.getAllEmployees().size()); 
     this.dispose(); 
     } catch (NamingException exception) { 
     loginButton.setEnabled(true); 
     passwordText.setEnabled(true); 
     usernameCombo.setEnabled(true); 
     loginButton.setIcon(IconFactory.getImageIcon(IconFactory.Icon.KEY, 16)); 
     JOptionPane.showMessageDialog(LoginFrame.this, "Login Error: " + exception.getMessage(), "Login Error! :: MachineryHub", JOptionPane.ERROR_MESSAGE); 
     } 
    } 
    } 

    private LoginService getLoginService() { 
    try { 
     Context c = new InitialContext(); 
     return (LoginService) c.lookup("ejb/machineryhub/LoginService"); 
    } catch (NamingException ne) { 
     throw new RuntimeException(ne); 
    } 
    } 
} 
+0

記錄調用了多少次'LoginCallbackHandler'。 – palacsint

+0

@palacsint它只在第一次嘗試登錄時被調用一次。第二次嘗試失敗時沒有調用「LoginCallbackHandler」。我非常有信心這是問題所在,但我不知道如何強制進行第二次認證嘗試。 – raistlin0788

+0

http://stackoverflow.com/questions/2758248/how-does-java-logincontext-login-work? – palacsint

回答

3

我還不能肯定這是最好的建議來解決這個問題方式,但我已經找到一種方法做我需要什麼。解決方案在於使用ProgrammaticLogin類。我刪除了LoginCallbackHandler類和參考application-client.xml。然後在登錄的代碼,只需創建InitialContext之前,我用下面的非常簡單的兩行:

ProgrammaticLogin pl = new ProgrammaticLogin(); 
pl.login(usernameCombo.getSelectedItem().toString(), passwordText.getPassword()); 

,這似乎不管我多少次輸入錯誤密碼的工作(你可以把這個限制以及一個簡單的計數器)。對於花費這麼長時間來弄清楚這一點我感到有點愚蠢,但是這個類並沒有出現在Netbeans中,因此我認爲它在Java EE 6中已經不再有效。但是,這僅僅是添加Glassfish/modules/security.jar到圖書館展示。

+1

感謝您分享。這個類沒有出現在Netbeans中的原因是它是一個依賴於應用服務器的解決方案,因此您不能與其他應用服務器(如JBoss等)一起使用。 – palacsint