带有Java限制的密码生成器

时间:2019-03-11 20:06:23

标签: java arrays random

我遇到了这个问题-我的密码必须至少包含8个字符,并且至少具有:

  • 1个大写字母
  • 1个小写字母
  • 1个特殊字符

该功能几乎可以按预期工作,但有时它不能满足上述密码的要求。如何修复我的代码,以确保每次生成的代码都符合要求?

public class PasswordGenerator {

private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz";
private static final String NUMBERS = "0123456789";
private static final String SPECIAL_CHARACTERS = "!@#$%^&*_=+-/.?<>)";

private static final String PASSWORD_BASE = CAPITAL_LETTERS + LOWERCASE_LETTERS + NUMBERS + SPECIAL_CHARACTERS;

public static String generateRandomPassword() {
    Random random = new Random();
    int randomPasswordLength = 8 + random.nextInt(7);
    System.out.println("random password length: " + randomPasswordLength);

    char[] generatedPassword = new char[randomPasswordLength];

    for(int i=0; i<randomPasswordLength; i++) {
        generatedPassword[i] = PASSWORD_BASE.charAt(random.nextInt(PASSWORD_BASE.length()));
    }


    return new String(generatedPassword);
}

2 个答案:

答案 0 :(得分:2)

一种方法是始终先生成这些特殊字符,然后随机完成密码。然后在末尾char[]进行随机排列以确保值的可预测性较低,并且不要以相同的符号组开头:

private static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz";
private static final String NUMBERS = "0123456789";
private static final String SPECIAL_CHARACTERS = "!@#$%^&*_=+-/.?<>)";
private static final String ALL_CHARACTERS = CAPITAL_LETTERS + LOWERCASE_LETTERS + NUMBERS + SPECIAL_CHARACTERS;
private static final Random RAND = new Random();

public static char[] generateRandomPassword() {
  int length = 8 + RAND.nextInt(7);
  char[] value = new char[length];
  value[0] = randomChar(CAPITAL_LETTERS);
  value[1] = randomChar(LOWERCASE_LETTERS);
  value[2] = randomChar(NUMBERS);
  value[3] = randomChar(SPECIAL_CHARACTERS);
  for (int i = 4; i < length; i++) {
    value[i] = randomChar(ALL_CHARACTERS);
  }
  shuffle(value);
  return value;
}

private static char randomChar(String str) {
  return str.charAt(RAND.nextInt(str.length()));
}

private static void shuffle(char[] array) {
  int index;
  char temp;
  for (int i = array.length - 1; i > 0; i--) {
    index = RAND.nextInt(i + 1);
    temp = array[index];
    array[index] = array[i];
    array[i] = temp;
  }
}

用于改组的额外代码基于this answer

请勿将密码存储为Stringit's less safe than char[]

答案 1 :(得分:1)

因此,基本上,您正在做的是将所有可能的字符添加到一个长字符串PASSWORD_BASE中。然后,您从该字符串中随机抽取8至12个字符,并将它们放在一起以设置密码。您的要求基本上只能靠运气来满足。可能的密码可能是aaaaaaaa

在不中断密码随机性的情况下,一种可能的简便修复方法可能是检查这种情况,如果不满足这些条件,我们只会生成另一种,直到我们满意为止。该方法可能如下所示:

public static String generateRandomPassword() {
    String generatedPassword;
    do {
        Random random = new Random();
        int randomPasswordLength = 8 + random.nextInt(7);
        System.out.println("random password length: " + randomPasswordLength);

        generatedPassword = "";

        for(int i=0; i<randomPasswordLength; i++) {
            generatedPassword += PASSWORD_BASE.charAt(random.nextInt(PASSWORD_BASE.length()));
        }
    } while (hasNoCommonElements(generatedPassword, CAPITAL_LETTERS) && 
             hasNoCommonElements(generatedPassword, NUMBERS) && 
             hasNoCommonElements(generatedPassword, SPECIAL_CHARACTERS));



    return new String(generatedPassword);
}

private static boolean hasNoCommonElements(String a, String b){
    for (char c : a.toCharArray()) {
        if(b.contains("" + c))
            return false;
    }
    return true;
}

请注意,此实现可能会任意运行,直到找到满足这些要求的密码。还要注意,到目前为止,这不是生成密码的最佳方法。但我希望这可以帮助您了解自己在做什么。