I already have a pretty basic Java Swing program but realised that I could do with a simple Username/password login screen to restrict access to it to only people with the username and password.
Is there anyway that I can insert some code to the start of the main method which will prevent execution beyond it until the username and password are entered on a screen that appears?
Here is an example of a Login Dialog. Closes entire program with close of Dialog.
Username: stackoverflow
Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if ("stackoverflow".equals(String.valueOf(jpfPassword.getPassword()))
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
You can use a DialogBox with Swing as soon as you execute your main
method. Then, based on the code, you can validate. If the values entered are ok with the authentication data (incoming from db, files, etc), then you show your main UI, if not, maybe you can show a dialog with something like "Try again" or close the dialog.
http://java.about.com/od/UsingDialogBoxes/a/How-To-Make-A-Password-Dialog-Box.htm
Hope it helps, best regards.
This is very tricky to do (as you probably realize), to ensure that someone can't sidestep your authentication.
If you don't care too much if someone can get past it, then an easy way to accomplish what you're trying would be to create a variable tracking login process and don't allow your main thread to start the GUI thread of the main application until the authentication is completed. Something like this would work:
public class MyApp {
private static boolean isAuthenticated;
public static void main( String args[] ) {
isAuthenticated = false;
while( !isAuthenicated ) {
authenticateUser();
try{ Thread.sleep( 200 ); } catch( InterruptedException ie ){ }
}
new JFrame();
// finish rest of GUI code.
}
private static void authenticateUser(){
dialog = new MyAuthenticationDialog();
dialog.show();
if( isValid( dialog.getUsername(), dialog.getPassword() )
isAuthenticated = true;
else
isAuthenticated = false;
}
}
If you care whether this can be reverse engineered however (this example would be trivial for me to RE), then you will need to have some encrypted value that uses the correct username and password as a key. Hash these together into a SHA-256 key and encrypt the value. Note that an RE could still bypass this but it will take more effort, especially if you repeatedly check that you can decrypt the value with the user provided credentials in random spots all through your code. Don't use a single function for it otherwise the RE need only patch that one function and his job is easy. At the end of the day you don't have control over the client so no solution will be perfect. These are some ideas. Also run your final code through a Java obfuscator.