I've found a component called JXLoginPane
from SwingX available in WindowBuilder and that seems like it would be a good starting point for what I am trying to do, but I need more information about how to use it. So far, the only thing I've found to really help me out with it is this 9-year-old blog post.
It does get me most of the way there, but there are several references to things like is.IS_Statics
, is.MD5Hash
, and isquote.Main
that the author does not provide. I am guessing that these are classes he or she has created just for logins, but I've no idea how to create them for myself.
How can I flesh out what Ruxton has started on his blog? Or, for that matter, can someone recommend an even better alternative to JXLoginPane
?
All answers will depend on your requirements, but most important thing is you understand what JXLoginPane
is and how it works. Then you will be able to understand that 9 years old post:
JXLoginPane: creates a panel with controls to authenticate users in a login based application.
LoginService: abstract base class that has to do the log-in logic and determine if user authentication is valid or not. It keeps an internal list of LoginListener
s object that are notified on LoginEvents during the whole login process: login started, canceled, succeeded and failed.
PasswordStore: abstract class intended to safely store passwords typed by users in some kind of cache, in order to help LoginService
to authenticate users. The actual mechanism used to store the passwords is left up to the implementation.
UserNameStore: same as PasswordStore
but for user names.
LoginListener: this interface provides a contract to "listen" the current login process and act in consequence. For example if a login attempt fails for the same user 5 times you could block that user assuming someone is trying to hack that account, or if login process succeeded then you could create a new session entry in your database if you are interested in keep a log table with users sessions.
Now taking a quick look to that post, I think it's a database service based implementation combined with Preferences based users names cache for UserNameStore
:
Class is.ISLoginService
is the LoginService
abstract base class implementation.
Class is.ISUserNameStore
is the UserNameStore
abstract class implementation.
There's no implementation for PasswordStore
abstract class.
Class is.ISLoginListener
is a LoginListener
interface implementation.
Finally, regarding is.IS_Statics
, is.MD5Hash
, and isquote.Main
seem to be utility classes of that specific project and have nothing to do with the essentials of JXLoginPane
. You will probably have your own classes that help you with login process.
Please consider this simple example that illustrates the concepts above described. You will see is not that difficult to make it work.
Note: there's no user name nor password store implementations.
Note 2: see LoginAdapter
import java.awt.event.WindowEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jdesktop.swingx.JXLoginPane;
import org.jdesktop.swingx.auth.LoginAdapter;
import org.jdesktop.swingx.auth.LoginEvent;
import org.jdesktop.swingx.auth.LoginListener;
import org.jdesktop.swingx.auth.LoginService;
public class Demo {
private JFrame frame;
private String userName;
private int failedAttemptsCount = 0;
private void showLoginDialog() {
frame = new JFrame("Welcome!");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final JXLoginPane loginPane = new JXLoginPane();
LoginListener loginListener = new LoginAdapter() {
@Override
public void loginFailed(LoginEvent source) {
failedAttemptsCount++;
String message;
switch(failedAttemptsCount) {
case 1: message = "Come on buddy! What happened?"; break;
case 2: message = "Did you just fail again?"; break;
case 3: message = "This is embarrassing..."; break;
default: message = "You should probably go home and get some sleep...";
}
loginPane.setErrorMessage(message);
}
@Override
public void loginSucceeded(LoginEvent source) {
Demo.this.userName = loginPane.getUserName();
Demo.this.createAndShowGui();
}
};
LoginService loginService = new LoginService() {
@Override
public boolean authenticate(String name, char[] password, String server) throws Exception {
return name.equals("Sturm")
&& String.valueOf(password).equals("StackOverflow") ;
}
};
loginService.addLoginListener(loginListener);
loginPane.setLoginService(loginService);
JXLoginPane.JXLoginDialog dialog = new JXLoginPane.JXLoginDialog(frame, loginPane);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
// if loginPane was cancelled or closed then its status is CANCELLED
// and still need to dispose main JFrame to exiting application
if(loginPane.getStatus() == JXLoginPane.Status.CANCELLED) {
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
}
private void createAndShowGui() {
String welcomeMessage = String.format("Welcome %s ! You have successfuly loged in.", userName);
JPanel panel = new JPanel();
panel.add(new JLabel(welcomeMessage));
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Demo().showLoginDialog();
}
});
}
}