Java EE 6应用程序客户端登录

时间:2011-10-05 15:23:59

标签: java security java-ee java-ee-6 application-client

我是Java EE的新手,刚开始使用我想创建的应用程序时遇到了很多麻烦。我想要的是连接到EJB项目的Swing应用程序客户端。我正在使用Glassfish v3.1.1。到目前为止我所拥有的是两个无状态bean,其中一个是使用@DeclareRoles和Glassfish中的JDBC领域以及客户端的开头来保护的。

运行客户端时,您可以选择用户名,键入密码,然后登录。如果您使用正确的密码,一切正常(客户端控制台吐出一些“安全”信息)。但是,如果您输入的密码不正确,则会被永久锁定。 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);
      }
    }
  }
}

现在是漫长的应用程序客户端。

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

1 个答案:

答案 0 :(得分:3)

我不肯定这是解决此问题的最佳推荐方法,但我找到了一种方法来完成我需要的工作。解决方案在于使用ProgrammaticLogin类。我从LoginCallbackHandler删除了application-client.xml类和引用。然后在登录代码中,就在创建InitialContext之前,我使用了以下非常简单的两行:

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

无论我输入错误密码多少次,这似乎都有效(您可以使用简单的计数器对此进行限制)。我花了这么长时间才弄清楚这一点感觉有点愚蠢,但是这个类并没有出现在Netbeans中所以我认为它在Java EE 6中不再有效。但是,这只是添加{ {1}}到库中显示它。