【问题标题】:Homework: Clearing the hash?作业:清除哈希?
【发布时间】:2016-10-06 20:52:38
【问题描述】:

我在 NetBeans IDE 8.1 中使用 Java8+

这是家庭作业的一部分,但这次我正在寻找答案。

我基本上只限于JDK,并且不允许使用以下代码:

  • 正则表达式
  • 缓冲阅读器
  • 尝试/抓住
  • 列表

基本上,我的选项仅限于变量、基本字符串方法(indexOf()、contain() 等)、for/while 循环、if/then 或 if/else、FileInputStream、Scanner 和其他非常基本的代码。即使使用我的分隔符将文件读入数组也可能有问题。

我有一些用于简单身份验证系统的代码。在一个文本文件中,我有 6 个“用户”,包括用户名、摘要、纯文本密码和他们的帐户角色。我已将文本文件拉入二维数组,并使用它进行比较。用户收到一个对话框输入用户名,然后另一个输入密码。 while 循环比较用户名和密码,然后报告Good login.Bad login. 问题是,它对第一个用户非常有效,或者如果输入了不正确的信息。对于用户 2-6,它陷入了“输入用户名和密码”的无限循环。下面是相关代码。另外,提前感谢您的帮助。

文件:credentials.txt: 分隔符是 \t(制表符)和 \r(回车)

griffin.keyes   108de81c31bf9c622f76876b74e9285f    alphabet soup   zookeeper
rosario.dawson  3e34baa4ee2ff767af8c120a496742b5    animal doctor   admin
bernie.gorilla  a584efafa8f9ea7fe5cf18442f32b07b    secret password veterinarian
donald.monkey   17b1b7d8a706696ed220bc414f729ad3    M0nk3y business zookeeper
jerome.grizzlybear  3adea92111e6307f8f2aae4721e77900    grizzly1234 veterinarian
bruce.grizzlybear   0d107d09f5bbe40cade3de5c71e9e9b7    letmein admin

对于主类:

import java.io.IOException;

public class TestAuthenticationSystem {
    public static void main(String[] args) throws IOException, Exception {
        TestSystemLogin sysLogin = new TestSystemLogin();  // Object of SystemLogin
        int loginCounter = 0;                      // Tracks login attempts.
        final int LOGIN_MAX = 3;                   // Max login attempts.

        // Have User attempt to login.
        while (loginCounter <= (LOGIN_MAX - 1)) {
            sysLogin.setCredArray();
            sysLogin.setCredentials();                     // Set credentials
            if (sysLogin.matchUsername(sysLogin.getCredArray(), sysLogin.getUsername()) == true) {
                if (sysLogin.passwordMatch(sysLogin.getCredArray(), sysLogin.getUsername())
                    == true) {
                    System.out.println("Good login.");
                    break;
                }
            else {
                ++loginCounter;
                System.out.println("Bad login.");
            }
            }
        }
    }
}

还有二等:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;

public class TestSystemLogin {
    private FileInputStream fileByteStream = null; // File input stream
    private Scanner inFS = null;                   // Scanner object
    final private Scanner input;
    private String username = "";                       // Holds username
    private String password = "";                       // Holds password
    private final String [][] credArray = new String[6][4];                 // Array for credentials.txt

    public TestSystemLogin() {
        this.input = new Scanner(System.in);
    }

    public void setCredentials() {
        System.out.println("Enter Username: ");
        username = input.next().toLowerCase();

        input.nextLine();
        System.out.println("Enter Password: ");
        password = input.nextLine();
    }

    // Return variable username.
    public String getUsername() {
        return username;
    }

    // Return variable password.
    public String getPassword() {
        return password;
    }

    public void setCredArray() throws IOException {
        int i = 0;                                 // Index variable
        int j = 0;                                 // Index variable

        // Import credentials data.
        fileByteStream = new FileInputStream("credentials.txt");
        inFS = new Scanner(fileByteStream);

        // Use carriage return and tab as token separators
        inFS.useDelimiter("[\\r\\t]");

        // Create array of credentials.txt
        for (i = 0; i < 6; ++i) {
            for (j = 0; j < 4; ++j) {
                credArray[i][j] = inFS.next();
            }
        }
        fileByteStream.close(); //Closes file.
    }    

    public String[][] getCredArray() {
        return credArray;
    }

    // Compare username to recorded username.
    public boolean matchUsername(String[][] credArray, String userUsername)           boolean isTrue = false;
        int i = 0;

        for (i = 0; i < credArray.length; ++i) {
            if (credArray[i][0].equals(userUsername)) {
                isTrue = true;
                break;
            }
        }        
        return isTrue; 
    }

public boolean passwordMatch(String[][] credArray, String userUsername) {
        boolean isTrue = false;
        int i = 0;

        for (i = 0; i < credArray.length; ++i) {
            if (credArray[i][0].equals(userUsername)) {
                if (credArray[i][2].equals(password)) {
                   isTrue = true;
                   break; 
                }                
            }
        }        
        return isTrue; 
    }

}

预期结果: 我可以输入 6 个用户名中的任何一个及其相应的密码,并收到“登录良好”。

发生了什么: 对于用户 2-6,我陷入了询问用户名和密码的无限循环。

以前的答案建议不要使用二维数组,将每个用户信息放入一个类中。在不创建其他类的情况下这可能吗?如果是这样,请为每个用户提供该类的示例,以及调用它的相应代码。

【问题讨论】:

  • 不要使用并行数组,创建一个类来保存每个用户的信息。此外,您不应该将明文密码存储在任何地方,这是一个安全问题,只需比较 MD5 哈希值即可。您也不需要在每次创建新的 MD5 实例时“清除哈希”。跟踪 IDE 调试器中的代码以查明问题所在。
  • @JimGarrison 是的,我完全同意你关于存储纯文本密码的安全风险的看法。在实时环境中,我永远不会这样做。对于这项任务,它是“按原样”分配给我们的,我们无法调整。
  • 哦不!其他人发表的评论似乎很好地解释了@JimGarrison 的建议,然后将其删除。
  • 看来你需要做一些调试。使用System.out.println 进行断点、断言语句和调试将成为您的朋友。堆栈溢出问题需要有一个minimal reproducible example
  • “如果不创建单独的类,这可能吗?” - 你已经有两个类,是否有禁止创建其他类的作业规则?如果您仅限于两个文件,您可以在TestSystemLogin 类中创建一个inner class,该类具有名称、哈希、密码和角色成员。

标签: java


【解决方案1】:

只有当错误的登录尝试次数 >= 3 时,您的 while 循环才会结束,否则,此无限循环将始终发生。此外,从文件中读取所有条目后,您需要另一个条件来终止循环。

建议您在每次迭代中读取文件,填充数组,关闭文件,继续整个过程,再次读取文件,填充数组并继续执行应该以仅读取文件的方式进行更改的操作一次,填充您的二维数组并进行比较。

【讨论】:

  • 如果登录成功,在弹出对话框后也应该break;。它适用于我的第一行用户。至于您的建议,您能否提供一些示例代码,关于我将如何处理多个用户?另外,澄清一下,我的credentials.txt 文件有 6 行,每列 4 列,每行由\t(制表符)分隔,第四列以\r(回车)结尾。我可以看到如何创建一个类来处理一个用户,在这种情况下是credArray[0][j],但是我将如何使用它来处理其他行?谢谢你的帮助。
  • 我编辑了我的原始问题以提供清晰性,并为了简洁而减少了代码。如果您能再次查看,将不胜感激。
【解决方案2】:

运行您的代码时,我在阅读凭证.txt 时遇到了问题。要验证您的代码是否在您的机器上正确读取了 credentials.txt,请通过将读取循环替换为

来输出您读取的数据
    // Create array of credentials.txt
    for (i = 0; i < NUM_ROWS_CRED; ++i) {
        for (j = 0; j < NUM_COLS_CRED; ++j) {
            String s = inFS.next();
            System.out.print(s+" ");
            credArray[i][j] = s;
        }
        System.out.println();
    }

最后,我不得不重新配置扫描仪以读取 credentials.txt 以接受换行符作为分隔符:

    // Use carriage return and tab as token separators
    inFS.useDelimiter("[\\r\\n\\t]");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 2013-09-02
    • 2014-03-10
    相关资源
    最近更新 更多