如何向现有 Java Swing 程序添加登录屏幕?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15908275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 21:15:30  来源:igfitidea点击:

How can I add a login screen to an existing Java Swing program?

javaswingsecurityuser-interface

提问by Mike

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.

我已经有了一个非常基本的 Java Swing 程序,但我意识到我可以使用一个简单的用户名/密码登录屏幕来限制只有拥有用户名和密码的人才能访问它。

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?

无论如何,我可以在 main 方法的开头插入一些代码,以防止在出现的屏幕上输入用户名和密码之前执行超出它的范围?

回答by Paul Samsotha

Here is an example of a Login Dialog. Closes entire program with close of Dialog.

这是登录对话框的示例。关闭整个程序并关闭 Dialog。

Username: stackoverflowPassword: stackoverflow

用户名:stackoverflow密码: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);
            }
        });
    }
}

回答by Marcelo Tataje

You can use a DialogBox with Swing as soon as you execute your mainmethod. 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.

您可以在执行main方法后立即将 DialogBox 与 Swing 结合使用。然后,根据代码,您可以验证。如果输入的值与身份验证数据(来自数据库、文件等)一致,那么您将显示您的主 UI,如果不是,也许您可​​以显示一个对话框,其中包含“再试一次”或关闭对话框。

http://java.about.com/od/UsingDialogBoxes/a/How-To-Make-A-Password-Dialog-Box.htm

http://java.about.com/od/UsingDialogBoxes/a/How-To-Make-A-Password-Dialog-Box.htm

Hope it helps, best regards.

希望它有所帮助,最好的问候。

回答by Freedom_Ben

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:

如果您不太关心是否有人可以通过它,那么完成您正在尝试的一种简单方法是创建一个变量跟踪登录过程,并且不允许您的主线程启动 GUI 线程主应用程序,直到身份验证完成。像这样的事情会起作用:

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.

但是,如果您关心这是否可以进行逆向工程(这个例子对我来说是微不足道的),那么您将需要一些使用正确用户名和密码作为密钥的加密值。将它们一起散列成一个 SHA-256 密钥并加密该值。请注意,RE 仍然可以绕过这一点,但需要更多的努力,特别是如果您反复检查是否可以在整个代码中的随机位置使用用户提供的凭据解密该值。不要为此使用单个函数,否则 RE 只需要修补那个函数,他的工作就很容易。归根结底,您无法控制客户端,因此没有任何解决方案是完美的。这是一些想法。还可以通过Java 混淆器运行您的最终代码。