Вход в клиент приложения Java EE 6

Я новичок в Java EE, и у меня было много проблем, когда я только начинал работу над приложением, которое я хочу создать. Я бы хотел, чтобы клиент приложения Swing подключался к проекту EJB. Я использую Glassfish v3.1.1. На данный момент у меня есть два bean-компонента без сохранения состояния, один из которых защищен с помощью @DeclareRoles и области JDBC в Glassfish, а также зачатки клиента.

Когда клиент запущен, вы можете выбрать имя пользователя, ввести пароль и, таким образом, войти в систему. При правильном пароле все работает (клиентская консоль плюется какой-то "защищенной" информацией). Однако, если вы введете неверный пароль, вы навсегда заблокируете доступ. InitialContext.lookup больше не вызывает CallbackHandler для проверки нового пароля, он продолжает использовать неправильные учетные данные.

Может кто-нибудь, пожалуйста, скажите мне, как это сделать правильно? Использую ли я правильный метод для этой ситуации - в Интернете огромное количество информации, но в основном нет примеров того, что я пытаюсь сделать? Кажется, все применимо только к J2EE или сервлетам! Вот некоторый соответствующий код.

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<?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>
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> к каждому создаваемому защищенному компоненту?

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

person raistlin0788    schedule 05.10.2011    source источник
comment
Запишите, сколько раз вызывали LoginCallbackHandler.   -  person palacsint    schedule 06.10.2011
comment
@palacsint Он вызывается только один раз, при первой попытке входа в систему. Вторая попытка завершается неудачно, без вызова LoginCallbackHandler. Я вполне уверен, что именно в этом и заключается проблема, но я понятия не имею, как принудительно выполнить вторую попытку аутентификации.   -  person raistlin0788    schedule 06.10.2011


Ответы (1)


Я не уверен, что это лучший или рекомендуемый способ решения этой проблемы, но я нашел способ сделать то, что мне нужно. Решение заключается в использовании класса 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 в библиотеки, чтобы он появился.

person raistlin0788    schedule 07.10.2011
comment
Спасибо, что поделились этим. Причина, по которой этот класс не появился в Netbeans, заключается в том, что это решение, зависящее от сервера приложений, поэтому вы не можете использовать его с другими серверами приложений (такими как JBoss и т. д.). - person palacsint; 10.10.2011