我对Java EE还很陌生,开始创建我想要的应用程序时遇到了很多问题。我想要的是一个连接到EJB项目的Swing应用程序客户端。我正在使用Glassfish v3.1.1。到目前为止,我有两个无状态bean,其中一个使用@DeclareRoles和Glassfish中的JDBC领域进行了安全保护,并开始创建客户端。
当运行客户端时,您可以选择用户名,输入密码,然后登录。如果您使用正确的密码,则一切正常(客户端控制台会输出一些“安全”信息)。但是,如果您输入错误的密码,您将被永久锁定。InitialContext.lookup不会再次调用CallbackHandler来检查新密码,它会继续使用不正确的凭据。
请问有人能告诉我如何正确地做这件事吗?我是否在使用适合这种情况的正确方法 - 网上有大量的信息,但基本上没有我正在尝试做的例子?似乎所有内容都只适用于J2EE或Servlets!以下是一些相关代码。
glassfish-ejb-jar.xml:
当运行客户端时,您可以选择用户名,输入密码,然后登录。如果您使用正确的密码,则一切正常(客户端控制台会输出一些“安全”信息)。但是,如果您输入错误的密码,您将被永久锁定。InitialContext.lookup不会再次调用CallbackHandler来检查新密码,它会继续使用不正确的凭据。
请问有人能告诉我如何正确地做这件事吗?我是否在使用适合这种情况的正确方法 - 网上有大量的信息,但基本上没有我正在尝试做的例子?似乎所有内容都只适用于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>
我需要为每个受保护的bean添加<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);
}
}
}
}
现在开始介绍一个较长的内容,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);
}
}
}
LoginCallbackHandler
被调用的次数。 - palacsintLoginCallbackHandler
。我相当有信心问题就出在这里,但我不知道如何强制进行第二次身份验证尝试。 - raistlin0788LoginContext
时,我遇到了不同的问题。LoginContext.login
似乎可以正常工作(没有异常),但是当我进行lookup
时,它会再次提示我使用内置的Glassfish提示输入用户名和密码。这当然会让我回到最初的问题,即在一次失败后防止我登录。根据此消息 ,我相信客户端容器应该负责除回调之外的所有内容。 - raistlin0788