Java 如何创建密码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1741160/
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-08-12 22:07:58  来源:igfitidea点击:

How can I create a password?

javasecurityrandompasswords

提问by Johanna

I want to give maybe a million password to some users that should be like:

我想给一些应该像这样的用户提供一百万个密码:

  1. It must have at least 6 characters
  2. It must have digits and also letters
  1. 它必须至少有 6 个字符
  2. 它必须有数字和字母

Should I use Randomhere? How?

我应该Random在这里使用吗?如何?

采纳答案by Romain Linsolas

RandomStringUtilsfrom Apache Commons Lang provide some methods to generate a randomized String, that can be used as password.

来自 Apache Commons Lang 的RandomStringUtils提供了一些生成随机字符串的方法,可以用作密码。



Here are some examples of 8-characters passwords creation:

以下是创建 8 个字符密码的一些示例:

// Passwords with only alphabetic characters.
for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.randomAlphabetic(8));
}
System.out.println("--------");
// Passwords with alphabetic and numeric characters.
for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.randomAlphanumeric(8));
}

which creates the following result:

这会产生以下结果:

zXHzaLdG
oDtlFDdf
bqPbXVfq
tzQUWuxU
qBHBRKQP
uBLwSvnt
gzBcTnIm
yTUgXlCc
--------
khDzEFD2
cHz1p6yJ
3loXcBau
F6NJAQr7
PyfN079I
8tJye7bu
phfwpY6y
62q27YRt

Of course, you have also methods that may restrict the set of characters allowed for the password generation:

当然,您还有一些方法可以限制生成密码所允许的字符集:

for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.random(8, "abcDEF123"));
}

will create only passwords with the characters a, b, c, D, E, F, 1, 2 or 3:

将仅创建包含字符 a、b、c、D、E、F、1、2 或 3 的密码:

D13DD1Eb
cac1Dac2
FE1bD2DE
2ab3Fb3D
213cFEFD
3c2FEDDF
FDbFcc1E
b2cD1c11

回答by Juha Syrj?l?

Use SecureRandom, it provides a more random passwords.

使用SecureRandom,它提供了更随机的密码。

You can create a single password using something like this (note: untested code).

您可以使用类似的方法创建单个密码(注意:未经测试的代码)。

// put here all characters that are allowed in password
char[] allowedCharacters = {'a','b','c','1','2','3','4'};

SecureRandom random = new SecureRandom();
StringBuffer password = new StringBuffer();

for(int i = 0; i < PASSWORD_LENGTH; i++) {
    password.append(allowedCharacters[ random.nextInt(allowedCharacters.length) ]);
}

Note that this does not guaranteethat the every password will have both digits and characters.

请注意,这并不能保证每个密码都包含数字和字符。

回答by Konamiman

What I would do is something like this:

我会做的是这样的:

  1. Create two arrays, one with the allowed letters and other with the allowed digits.
  2. Use Random to decide the length of the password.
  3. Use Random to decide whether the next character is a letter or a digit.
  4. Use Random once more to generate an index for the array of letters or digits (depending on wht you obtained in step 3). Append the obtained character to the password.
  5. Repeat from 3 until you have the amount of characters obtained in 2.
  1. 创建两个数组,一个包含允许的字母,另一个包含允许的数字。
  2. 使用 Random 决定密码的长度。
  3. 使用 Random 决定下一个字符是字母还是数字。
  4. 再次使用 Random 为字母或数字数组生成索引(取决于您在步骤 3 中获得的内容)。将获取的字符附加到密码中。
  5. 从 3 开始重复,直到获得在 2 中获得的字符数。

回答by Suraj Chandran

This will be the easiest one :)

这将是最简单的一个:)

String char_group = "abcdefghijklmnopqrstuvwxyz";
String digit_group = "123456789";

// first choose a len of pwd
Random ran = new Random();
int pwd_len = ran.nextInt(50); //50 is the max length of password,say
// check that pwd_len is not less than 6
// do the check here

// finally create the password..
StringBuffer pwd = new StringBuffer();
Random RNG = new Random();
for (int i = 0; i < pwd_len ; i++) {
    int randomNum = RNG.nextInt(100);
    char c = '';
    // Here 25% is the ratio of mixing digits
    // in the password, you can change 4 to any
    // other value to change the depth of mix
    // or you can even make it random. 
    if (randomNum % 4 == 0) {
        c = digit_group[randomNum  % digit_group.length];
    } else {
        c = char_group[randomNum  % char_group.length];
    }
    pwd.append(c);
}
return pwd.toString();

回答by BalusC

This is also a nice one:

这也是一个不错的:

String password = Integer.toString((int) (Math.random() * Integer.MAX_VALUE), 36);

It however does not guarantee that the password alwayscontains bothdigits and letters, but most of the aforementioned suggestions also doesn't do that.

然而它并不能保证密码总是包含两个数字和字母,但大多数的上述建议,还没有做到这一点。

回答by crowne

Here's one that I wrote a while back:

这是我不久前写的一个:

package com.stackoverflow.does.my.code.for.me;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

public class PasswordUtil {

    /** Minimum password length = 6 */
    public static final int MIN_PASSWORD_LENGTH = 6;
    /** Maximum password length = 8 */
    public static final int MAX_PASSWORD_LENGTH = 8;

    /** Uppercase characters A-Z */
    public static final char[] UPPERS = new char[26];
    /** Lowercase characters a-z */
    public static final char[] LOWERS = new char[26];
    /**
     * Printable non-alphanumeric characters, excluding space.
     */
    public static final char[] SPECIALS = new char[32];
    public static final char[] DIGITS = new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    static {
        // Static initializer block for populating arrays
        int U = 'A';
        int l = 'a';
        int d = '0';
        for (int i = 0; i < 26; i++) {
            UPPERS[i] = (char) (U + i);
            LOWERS[i] = (char) (l + i);
            if (i < 10) {
                DIGITS[i] = (char) (d + i);
            }
        }
        int p = 0;
        for (int s = 33; s < 127; s++) {
            char specialChar = (char) 32;

            if (s >= 'a' && s <= 'z')
                s = 'z' + 1; // jump over 'a' to 'z'
            else if (s >= 'A' && s <= 'Z')
                s = 'Z' + 1; // jump over 'A' to 'Z'
            else if (s >= '0' && s <= '9')
                s = '9' + 1; // jump over '0' to '9'

            specialChar = (char) s;
            SPECIALS[p] = specialChar;
            p++;
        }
    }

    public String generatePassword() {
        List<char[]> activeSets = new ArrayList<char[]>(4);
        List<char[]> inactiveSets = new ArrayList<char[]>(4);

        activeSets.add(UPPERS);
        activeSets.add(LOWERS);
        activeSets.add(SPECIALS);
        activeSets.add(DIGITS);

        SecureRandom random = new SecureRandom();

        int passwordLength = 5 + random.nextInt(3);
        StringBuffer password = new StringBuffer(passwordLength + 1);

        for (int p = 0; p <= passwordLength; p++) {
            char[] randomSet = null;
            if (activeSets.size() > 1) {
                int rSet = random.nextInt(activeSets.size());
                randomSet = activeSets.get(rSet);
                inactiveSets.add(randomSet);
                activeSets.remove(rSet);
            } else {
                randomSet = activeSets.get(0);
                inactiveSets.add(randomSet);
                activeSets.clear();
                activeSets.addAll(inactiveSets);
                inactiveSets.clear();
            }
            int rChar = random.nextInt(randomSet.length);
            char randomChar = randomSet[rChar];
            password.append(randomChar);
        }

        return password.toString();
    }
}

回答by falsarella

When using Apache's RandomStringUtilsfor security reasons (i.e. passwords), it's very important to combine the use of a SecureRandomsource:

RandomStringUtils出于安全原因(即密码)使用 Apache 时,结合使用SecureRandom源非常重要:

RandomStringUtils.random(6, 0, 0, true, true, null, new SecureRandom());

回答by Wouter Verleur

A bit late, but I usually use the following code:

有点晚了,但我通常使用以下代码:

private static final int PASSWORD_SIZE = 16;
private static final String VALID_SPECIAL_CHARACTERS = "!@#$%&*()_-+=[]{}\|:/?.,><"; // Note the double \ as escape

private static String createPassword() {
    SecureRandom random = new SecureRandom();
    StringBuilder password = new StringBuilder();
    while (password.length() < PASSWORD_SIZE) {
        char character = (char) random.nextInt(Character.MAX_VALUE);
        if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9') || VALID_SPECIAL_CHARACTERS.contains(String.valueOf(character))) {
            password.append(character);
        }
    }
    return password.toString();
}

There is no guarantee that there will always be a number, special character, lower-case and upper-case character in the password. This could be enforced by first adding a character and a digit, however this would create passwords that are a bit more predictable.

不能保证密码中总是有数字、特殊字符、小写和大写字符。这可以通过首先添加一个字符和一个数字来强制执行,但这会创建更可预测的密码。

回答by Leo

Here is how you can make sure your generated password meets your password criteria, e.g: in your case, i would use this regex:

以下是确保生成的密码符合密码标准的方法,例如:在您的情况下,我将使用此正则表达式:

<code>String regex = "^(?=[a-zA-Z0-9??]*\d)(?=[a-zA-Z0-9??]*[a-z])(?=[a-zA-Z0-9??]*[A-Z])[a-zA-Z0-9??]{6,}$"</code>

This regex meets the following criteria:

此正则表达式满足以下条件:

1.- at least 1 lowerCase letter

1.- 至少 1 个小写字母

2.- at least 1 upperCase letter

2.- 至少 1 个大写字母

3.- at least 1 digit(number)

3.- 至少 1 位数字(数字)

4.- at least 6 characters (note that adding a number greater than 6 after the comma at the end of the regex, will now meet a criteria that at least 6 characters and a max of whatever you put in there)

4.- 至少 6 个字符(请注意,在正则表达式末尾的逗号后添加一个大于 6 的数字,现在将满足至少 6 个字符和最多输入的任何内容的条件)

<code>char[] char = {'a','b','c','d','e','f','g','h',...};

SecureRandom random = new SecureRandom();
StringBuffer password = new StringBuffer();</code>

while(!password.toString().matches("your regex")){
    for(int i = 0; i < 8; i++) {
    password.append(char [ random.nextInt(char .length) ]);
    }
}
System.out.println(password.toString());

What this code does is that whileyour generated password doesn't meet your criteria, it will loop the forloop over and over.

这段代码的作用是while您生成的密码不符合您的标准,它会for一遍又一遍地循环。

回答by AlikElzin-kilaka

Implemented a PasswordBuilder. Supports passwrod limit, must have characters and how much of them, char ranges and a list of them.

实现了一个PasswordBuilder。支持密码限制,必须有字符和它们的数量,字符范围和它们的列表。

Usage Example:

用法示例:

System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).build());

Example result: QU1GY7p+j+-PUW+_

结果示例: QU1GY7p+j+-PUW+_

System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).setSize(5).build());

Example result: %,4NX

结果示例: %,4NX

Implementation:

执行:

//Version=1.0
//Source=https://www.dropbox.com/s/3a4uyrd2kcqdo28/PasswordBuilder.java?dl=0
//Dependencies=java:7 com.google.guava:guava:18.0 commons-lang:commons-lang:2.6

import com.google.common.primitives.Chars;
import org.apache.commons.lang.ArrayUtils;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by alik on 5/26/16.
 */
public class PasswordBuilder {
    private int size = 16;
    private List<Character> options = new ArrayList<>();
    private Map<List<Character>, Integer> musts = new java.util.LinkedHashMap<>();
    private SecureRandom secureRandom = new SecureRandom();

    public PasswordBuilder() {
    }

    public PasswordBuilder setSize(int size) {
        this.size = size;
        return this;
    }

    public PasswordBuilder addRangeOption(char from, char to, int mustCount) {
        List<Character> option = new ArrayList<>(to - from + 1);
        for (char i = from; i < to; ++i) {
            option.add(i);
        }
        return addOption(option, mustCount);
    }

    public PasswordBuilder addCharsOption(String chars, int mustCount) {
            return addOption(Chars.asList(chars.toCharArray()), mustCount);
    }

    public PasswordBuilder addOption(List<Character> option, int mustCount) {
        this.options.addAll(option);
        musts.put(option, mustCount);
        return this;

    }

    public String build() {
        validateMustsNotOverflowsSize();
        Character[] password = new Character[size];

        // Generate random from musts
        for (Map.Entry<List<Character>, Integer> entry : musts.entrySet()) {
            for (int i = 0; i < entry.getValue(); i++) {
                int charIndex = secureRandom.nextInt(entry.getKey().size());
                char c = entry.getKey().get(charIndex);
                addChar(password, c);
            }
        }

        // Generate from overall
        for (int i = 0; i < password.length; i++) {
            if (password[i] != null) continue;
            password[i] = options.get(secureRandom.nextInt(options.size()));
        }
        return new String(ArrayUtils.toPrimitive(password));
    }

    private void addChar(Character[] password, char c) {
        int i;
        for (i = secureRandom.nextInt(password.length); password[i] != null; i = secureRandom.nextInt(password.length)) {
        }
        password[i] = c;
    }

    private void validateMustsNotOverflowsSize() {
        int overallMusts = 0;
        for (Integer mustCount : musts.values()) {
            overallMusts += mustCount;
        }
        if (overallMusts > size) {
            throw new RuntimeException("Overall musts exceeds the requested size of the password.");
        }
    }

    public static void main(String[] args) {
        System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).build());
        System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).setSize(5).build());
    }
}