我正在尝试创建一个Java程序,用于生成密码,可以是全小写、小写和大写、小写和大写的数字、小写和大写的数字和标点符号中的任意一种,并且该程序还必须创建用户选择的密码,并根据用户选择生成密码长度。我已经生成了供用户选择的密码选项并提示他选择一个。现在我卡在如何创建上述密码类型。有人建议我使用ASCII值,然后将它们转换为文本。我知道如何将它们转换为文本,但它会显示数字、字母和标点符号。是否有任何方法可以仅为小写字母生成ASCII值?另外,如何根据用户给出的长度生成密码?
我正在尝试创建一个Java程序,用于生成密码,可以是全小写、小写和大写、小写和大写的数字、小写和大写的数字和标点符号中的任意一种,并且该程序还必须创建用户选择的密码,并根据用户选择生成密码长度。我已经生成了供用户选择的密码选项并提示他选择一个。现在我卡在如何创建上述密码类型。有人建议我使用ASCII值,然后将它们转换为文本。我知道如何将它们转换为文本,但它会显示数字、字母和标点符号。是否有任何方法可以仅为小写字母生成ASCII值?另外,如何根据用户给出的长度生成密码?
我使用这个不可变类。
它使用构建器模式。
它不支持扩展。
public final class PasswordGenerator {
private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String PUNCTUATION = "!@#$%&*()_+-=[]|,./?><";
private boolean useLower;
private boolean useUpper;
private boolean useDigits;
private boolean usePunctuation;
private PasswordGenerator() {
throw new UnsupportedOperationException("Empty constructor is not supported.");
}
private PasswordGenerator(PasswordGeneratorBuilder builder) {
this.useLower = builder.useLower;
this.useUpper = builder.useUpper;
this.useDigits = builder.useDigits;
this.usePunctuation = builder.usePunctuation;
}
public static class PasswordGeneratorBuilder {
private boolean useLower;
private boolean useUpper;
private boolean useDigits;
private boolean usePunctuation;
public PasswordGeneratorBuilder() {
this.useLower = false;
this.useUpper = false;
this.useDigits = false;
this.usePunctuation = false;
}
/**
* Set true in case you would like to include lower characters
* (abc...xyz). Default false.
*
* @param useLower true in case you would like to include lower
* characters (abc...xyz). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useLower(boolean useLower) {
this.useLower = useLower;
return this;
}
/**
* Set true in case you would like to include upper characters
* (ABC...XYZ). Default false.
*
* @param useUpper true in case you would like to include upper
* characters (ABC...XYZ). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useUpper(boolean useUpper) {
this.useUpper = useUpper;
return this;
}
/**
* Set true in case you would like to include digit characters (123..).
* Default false.
*
* @param useDigits true in case you would like to include digit
* characters (123..). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useDigits(boolean useDigits) {
this.useDigits = useDigits;
return this;
}
/**
* Set true in case you would like to include punctuation characters
* (!@#..). Default false.
*
* @param usePunctuation true in case you would like to include
* punctuation characters (!@#..). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder usePunctuation(boolean usePunctuation) {
this.usePunctuation = usePunctuation;
return this;
}
/**
* Get an object to use.
*
* @return the {@link gr.idrymavmela.business.lib.PasswordGenerator}
* object.
*/
public PasswordGenerator build() {
return new PasswordGenerator(this);
}
}
/**
* This method will generate a password depending the use* properties you
* define. It will use the categories with a probability. It is not sure
* that all of the defined categories will be used.
*
* @param length the length of the password you would like to generate.
* @return a password that uses the categories you define when constructing
* the object with a probability.
*/
public String generate(int length) {
// Argument Validation.
if (length <= 0) {
return "";
}
// Variables.
StringBuilder password = new StringBuilder(length);
Random random = new Random(System.nanoTime());
// Collect the categories to use.
List<String> charCategories = new ArrayList<>(4);
if (useLower) {
charCategories.add(LOWER);
}
if (useUpper) {
charCategories.add(UPPER);
}
if (useDigits) {
charCategories.add(DIGITS);
}
if (usePunctuation) {
charCategories.add(PUNCTUATION);
}
// Build the password.
for (int i = 0; i < length; i++) {
String charCategory = charCategories.get(random.nextInt(charCategories.size()));
int position = random.nextInt(charCategory.length());
password.append(charCategory.charAt(position));
}
return new String(password);
}
}
这是一个用法示例,
PasswordGenerator passwordGenerator = new PasswordGenerator.PasswordGeneratorBuilder()
.useDigits(true)
.useLower(true)
.useUpper(true)
.build();
String password = passwordGenerator.generate(8); // output ex.: lrU12fmM 75iwI90o
.useUpper(true)
,密码可能不包含任何大写字符。 - frzsombor万一有人需要,这是一个基于ASCII范围的标准Java 8类的单行随机密码生成器:
String password = new Random().ints(10, 33, 122).collect(StringBuilder::new,
StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
或者String password = new Random().ints(10, 33, 122).mapToObj(i -> String.valueOf((char)i)).collect(Collectors.joining());
这里密码的长度为10。当然,您也可以在某个范围内随机设置它。 并且字符来自ASCII范围33-122,这些都是特殊符号、数字、大写和小写字母。
如果您只需要小写字母,只需设置范围为:97-122
ints()
的最后一个参数是左闭右开区间,因此这不会包括代码点 122(_z_),应该改为 123。如果您使用特殊字符,最好将其提高到 127,其中包括 {, |, }, 和 _~_。 - Raniznew Random()
换成new SecureRandom()
,把.ints(10, 33, 122)
改为更易懂的.ints(10, '!', '{')
。 - Andriy Kryvtsunimport java.security.SecureRandom;
import java.util.Random;
public class PasswordHelper {
public static String generatePassword (int length) {
//minimum length of 6
if (length < 4) {
length = 6;
}
final char[] lowercase = "abcdefghijklmnopqrstuvwxyz".toCharArray();
final char[] uppercase = "ABCDEFGJKLMNPRSTUVWXYZ".toCharArray();
final char[] numbers = "0123456789".toCharArray();
final char[] symbols = "^$?!@#%&".toCharArray();
final char[] allAllowed = "abcdefghijklmnopqrstuvwxyzABCDEFGJKLMNPRSTUVWXYZ0123456789^$?!@#%&".toCharArray();
//Use cryptographically secure random number generator
Random random = new SecureRandom();
StringBuilder password = new StringBuilder();
for (int i = 0; i < length-4; i++) {
password.append(allAllowed[random.nextInt(allAllowed.length)]);
}
//Ensure password policy is met by inserting required random chars in random positions
password.insert(random.nextInt(password.length()), lowercase[random.nextInt(lowercase.length)]);
password.insert(random.nextInt(password.length()), uppercase[random.nextInt(uppercase.length)]);
password.insert(random.nextInt(password.length()), numbers[random.nextInt(numbers.length)]);
password.insert(random.nextInt(password.length()), symbols[random.nextInt(symbols.length)]);
}
return password.toString();
}
}
George Siggouroglou创建了一个非常好的答案。我用更加灵活的方式修改和完善了他的代码。
SecureRandom
代替Random
。你可以将其改为Random
。custom
方法来自定义词汇表。public class Main {
public static void main(String[] args) {
String password = new PasswordGenerator.Builder()
.digits(4)
.lower(1)
.upper(2)
.punctuation()
.generate(10);
System.out.println(password);
// with custom
password = new PasswordGenerator.Builder()
.custom("1579", 1)
.custom("Stackoverflow", 3)
.lower()
.generate(6);
System.out.println(password);
}
}
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PasswordGenerator {
private final List<Rule> rules;
private PasswordGenerator() {
throw new UnsupportedOperationException("Empty constructor is not supported.");
}
private PasswordGenerator(Builder builder) {
this.rules = builder.rules;
}
public String generate(int length) {
if (length <= 0) {
return "";
}
// shuffle rules
List<Rule> shuffledRules = new ArrayList<>(rules);
Collections.shuffle(shuffledRules);
// random instance, you can use `Random random = new Random();`
Random random = new SecureRandom();
// 1. STAGE - SELECT MINIMUM CHARACTERS FROM RULES THAT HAVE MINIMUM COUNT.
List<Character> selectedChars = new ArrayList<>(selectCharactersByMinimumCount(random, shuffledRules));
// 2. STAGE - SELECT MISSING LENGTH FROM ALL AVAILABLE CHARACTERS
int missingLength = length - selectedChars.size();
if (missingLength > 0) {
selectedChars.addAll(selectCharactersByMissingLength(random, shuffledRules, missingLength));
}
// 3. STAGE - SHUFFLE SELECTED CHARS
Collections.shuffle(selectedChars);
// 4. STAGE - RETURN RESULT
return selectedChars.stream().map(String::valueOf).collect(Collectors.joining());
}
/**
* Select random characters from filter rules that they are defined minimum count value.
*
* @param random Random instance
* @param rules Rules
* @return Randomly chosen characters
*/
private List<Character> selectCharactersByMinimumCount(Random random, List<Rule> rules) {
return rules.stream()
.filter(rule -> rule.minimumCount > 0)
.flatMap(rule ->
IntStream.range(0, rule.minimumCount)
.mapToObj(i -> rule.text.charAt(random.nextInt(rule.text.length()))))
.collect(Collectors.toList());
}
/**
* Select random characters from all filter rules up to complete required characters count.
*
* @param random Random instance
* @param rules Rules
* @return Randomly chosen characters
*/
private List<Character> selectCharactersByMissingLength(Random random, List<Rule> rules, int missingLength) {
List<Character> availableList = rules.stream()
.flatMap(rule -> rule.text.chars().mapToObj(c -> (char) c))
.collect(Collectors.toList());
// shuffle available list
Collections.shuffle(availableList);
return IntStream.range(0, missingLength)
.mapToObj(i -> availableList.get(random.nextInt(availableList.size()))).collect(Collectors.toList());
}
public static class Builder {
private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String PUNCTUATION = "!@#$%&*+-";
private final List<Rule> rules = new ArrayList<>();
public Builder digits() {
return custom(DIGITS, 0);
}
public Builder digits(int minimumCount) {
return custom(DIGITS, minimumCount);
}
public Builder lower() {
return lower(0);
}
public Builder lower(int minimumCount) {
return custom(LOWER, minimumCount);
}
public Builder upper() {
return upper(0);
}
public Builder upper(int minimumCount) {
return custom(UPPER, minimumCount);
}
public Builder punctuation() {
return punctuation(0);
}
public Builder punctuation(int minimumCount) {
return custom(PUNCTUATION, minimumCount);
}
public Builder custom(String text) {
return custom(text, 0);
}
public Builder custom(String text, int minimumCount) {
rules.add(new Rule(text, minimumCount));
return this;
}
public PasswordGenerator build() {
return new PasswordGenerator(this);
}
public String generate(int length) {
return build().generate(length);
}
}
private static class Rule {
private final String text;
private final int minimumCount;
public Rule(String text, int minimumCount) {
this.text = text;
this.minimumCount = minimumCount;
}
}
}
这是 George Siggouroglou 的答案(点击查看)的简略版本,虽然不够灵活但更为简短。
public final class DefaultPasswordGenerator {
private static final String[] charCategories = new String[] {
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789"
};
public static String generate(int length) {
StringBuilder password = new StringBuilder(length);
Random random = new Random(System.nanoTime());
for (int i = 0; i < length; i++) {
String charCategory = charCategories[random.nextInt(charCategories.length)];
int position = random.nextInt(charCategory.length());
password.append(charCategory.charAt(position));
}
return new String(password);
}
}
String passWord = PasswordGenerator.generate(10);
String lower = "abc...xyz";
String digits = "0123456789";
String punct = "!#$&...";
String ... // further characer classes
请注意...
部分需要自己填写。
从用户选择的选项中,通过连接相应的字符类别创建一个可供选择的字符字符串。
最后你要运行一个循环n次,其中n是所需字符的数量。每一轮中,你从所创建的字符串中随机选择一个字符并将其添加到结果中:
StringBuilder sb = new StringBuilder();
int n = ....; // how many characters in password
String set = ....; // characters to choose from
for (i= 0; i < n; i++) {
int k = ....; // random number between 0 and set.length()-1 inklusive
sb.append(set.charAt(k));
}
String result = sb.toString();
Apache commons text有一个非常好的随机字符串生成的替代方案。使用Builder来构建生成器,然后可以轻松地使用该生成器来生成所需的密码。
// Generates a 20 code point string, using only the letters a-z
RandomStringGenerator generator = new RandomStringGenerator.Builder()
.withinRange('a', 'z').build();
String randomLetters = generator.generate(20);
public static final String upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lowerChars = "abcdefghijklmnopqrstuvwxyz";
public static final String numbers = "1234567890";
public static final String specialChars = "!@#$%^&*()_+{}";
public static String generatePassword(
int passwordSize,
boolean useUpper,
boolean useLower,
boolean useNumbers,
boolean useSpecial
) {
char[] password = new char[passwordSize];
String charSet = null;
Random random = new Random();
if (useUpper) charSet += upperChars;
if (useLower) charSet += lowerChars;
if (useNumbers) charSet += numbers;
if (useSpecial) charSet += specialChars;
for (int i = 0; i < passwordSize; i++) {
password[i] = charSet.toCharArray()[random.nextInt(charSet.length() - 1)];
}
return String.valueOf(password);
}
使用方法
generatePassword(22, true, true, true, true);
这将返回一个字符串,因此可以直接使用而不需要转换。