2011-10-05 91 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