Java密码生成器

时间:2013-11-02 14:49:16

标签: java passwords generator

我正在尝试创建一个创建密码的java程序,全部是小写,小写和大写,小写和大写以及数字,小写和大写以及数字和标点符号,程序还必须创建其中一个密码,用户选择并且必须根据用户选择的内容生成密码长度。我已经为用户选择了密码选项,并提示他选择一个。我现在仍然坚持如何创建上面提到的密码类型。一个人建议我使用ASCII值,然后将它们转换为文本。我知道如何将它们转换为文本,但它会显示数字,字母和标点符号。有没有什么办法可以只为小写字母生成ASCII值?另外,我将如何根据用户提供的密码生成密码?

13 个答案:

答案 0 :(得分:34)

我使用这个不可变的类 它使用构建器模式 它不支持扩展

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

答案 1 :(得分:17)

您可以使用org.apache.commons.lang.RandomStringUtils生成随机文本/密码。例如,请参阅this链接。

答案 2 :(得分:4)

以防万一对某人有用。标准Java 8类基于ASCII范围的单行随机密码生成器:

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

答案 3 :(得分:3)

你可以这样做:

String lower = "abc...xyz";
String digits = "0123456789";
String punct = "!#$&...";
String  ...                      // further characer classes

(请注意您必须自己填写的...部分。)

从用户选择的选项中,您可以通过连接相应的字符类来创建可供选择的字符串。

最后你运行一个循环n次,其中n是想要的字符数。 在每一轮中,您从您创建的String中选择一个随机字符并将其添加到结果中:

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();

答案 4 :(得分:2)

Apache commons text对随机字符串生成有很好的选择。生成器用于构建生成器,此生成器易于用于生成所需的密码。

 // 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);

请参阅

https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/RandomStringGenerator.html

答案 5 :(得分:2)

George Siggouroglou's answer的灵活性较差,但版本较短。

发电机类

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);

答案 6 :(得分:2)

还有另一个随机字符串生成器

George Siggouroglou 创建了一个非常好的答案。我已经开发并更灵活地更改了他的代码。

特点

  1. 使用 SecureRandom 而不是 Random。你可以用 Random 代替它。
  2. 添加了最少字符数。首先,算法通过最小字符随机选择字符。选择最少所需字符后,将在所有可用字符中使用其余字符完成。然后随机交换所有选定的字符。
  3. 您可以通过 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;
        }
    }
}

答案 7 :(得分:1)

您可以随意选择具有尺寸的数字,字母和标点符号。 Ansi数字从30到39,小写字母从61-7A,ans等等。使用ansii tables

答案 8 :(得分:0)

如果是我,我会建立代表您允许的各种字符集的字符数组(char[] ...),然后在您的生成器方法中选择适当的字符数组,并生成密码从那以后。复杂的部分然后变得创建字符数组......

public String generate(char[] validchars, int len) {
    char[] password = new char[len];
    Random rand = new Random(System.nanoTime());
    for (int i = 0; i < len; i++) {
        password[i] = validchars[rand.nextInt(validchars.length)];
    }
    return new String(password);
}

然后你的问题只是生成char []数组,代表你拥有的各种规则,以及如何将该集合传递给generate方法。

这样做的一种方法是设置一个与您允许的规则匹配的正则表达式规则列表,然后通过规则发送每个字符....如果它们符合规则,则添加它们...... ..

考虑一个看起来像这样的函数:

public static final char[] getValid(final String regex, final int lastchar) {
    char[] potential = new char[lastchar]; // 32768 is not huge....
    int size = 0;
    final Pattern pattern = Pattern.compile(regex);
    for (int c = 0; c <= lastchar; c++) {
        if (pattern.matcher(String.valueOf((char)c)).matches()) {
            potential[size++] = (char)c;
        }
    }
    return Arrays.copyOf(potential, size);
}

然后,您可以使用以下命令获取一组无字符字符(仅限小写)

getValid("[a-z]", Character.MAX_VALUE);

或者,所有单词的列表&#39;字符:

getValid("\\w", Character.MAX_VALUE);

然后,选择正则表达式以符合您的要求,并且存储&#39;每次都要重用的有效字符数组。 (每次生成密码时都不要生成字符....)

答案 9 :(得分:0)

您可以尝试使用Unix&#34; pwgen&#34;的Java实现。 https://github.com/antiso/pwgen-gae 它包含指向Bitbucket的CLI的jpwgen库实现的链接以及GAE部署样本的链接。

答案 10 :(得分:0)

我创建了一个简单的程序,用{ASCII}编号填充ArrayList,然后使用SecureRandom数字生成器在for循环中从它们中随机化,您可以在其中设置你想要的字符数。

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

public class PassGen {

    private String str;
    private int randInt;
    private StringBuilder sb;
    private List<Integer> l;

    public PassGen() {
        this.l = new ArrayList<>();
        this.sb = new StringBuilder();

        buildPassword();
    }

    private void buildPassword() {

        //Add ASCII numbers of characters commonly acceptable in passwords
        for (int i = 33; i < 127; i++) {
            l.add(i);
        }

        //Remove characters /, \, and " as they're not commonly accepted
        l.remove(new Integer(34));
        l.remove(new Integer(47));
        l.remove(new Integer(92));

        /*Randomise over the ASCII numbers and append respective character
          values into a StringBuilder*/
        for (int i = 0; i < 10; i++) {
            randInt = l.get(new SecureRandom().nextInt(91));
            sb.append((char) randInt);
        }

        str = sb.toString();
    }

    public String generatePassword() {
        return str;
    }
}

希望这有帮助! :)

答案 11 :(得分:0)

import 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();

    }

}

答案 12 :(得分:0)

version: '2'
services:
  myapp:
    image: 'bitnami/symfony:1'
    ports:
      - '8000:8000'
    volumes:
      - '.:/app'
    environment:
      - SYMFONY_PROJECT_NAME=backend
      - MARIADB_HOST=mariadb
      - MARIADB_PORT_NUMBER=3306 
      - MARIADB_USER=monty
      - MARIADB_PASSWORD=monty
      - MARIADB_DATABASE=ecommerce
    user: "1000"
    container_name: backend
    depends_on:
      - mariadb
  frontend:
    build: ./frontend
    ports:
      - ${FRONTEND_PORT}:${FRONTEND_PORT}
    volumes:
      - ./frontend/:/usr/src/app/
    container_name: frontend
  mariadb:
    image: 'bitnami/mariadb:10.3'
    ports:
      - '3306:3306'
    volumes:
      - ./data:/bitnami/mariadb:rw
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - MARIADB_DATABASE=ecommerce
      - MARIADB_PORT_NUMBER=3306
      - MARIADB_ROOT_USER=root
      - MARIADB_USER=monty
      - MARIADB_PASSWORD=monty
    user: "1000"
    container_name: mariadb