简体   繁体   English

JavaScript 密码生成器有时不包括字符选择?

[英]JavaScript Password Generator Sometimes Not Including Character Selections?

Hello Stack Overflow!你好堆栈溢出!

This is my first time posting on the site so please bare with me and my question.这是我第一次在网站上发帖,所以请坦白我和我的问题。 My class was tasked with individually creating a password generator using JavaScript.我的 class 的任务是使用 JavaScript 单独创建密码生成器。 Thankfully I had gotten most of the application operating correctly, but I've gotten stuck on a problem.谢天谢地,我已经让大部分应用程序正常运行,但我遇到了一个问题。

Example: The user chooses to have 8 characters in their password and chooses to include special, lowercase, and uppercase characters.示例:用户选择在密码中包含 8 个字符,并选择包含特殊字符、小写字符和大写字符。 When the password is generated sometimes it won't include all of the character selections.有时生成密码时,它不会包含所有字符选择。 (Sometimes it'll generate a password with both special and uppercase characters, but not have a single lowercase character). (有时它会生成一个包含特殊字符和大写字符的密码,但没有一个小写字符)。

I've been finished with this assignment for a minute now, but my goal is to understand what I can do to fix this problem and complete this app anyway.我已经完成了这个任务一分钟,但我的目标是了解我可以做些什么来解决这个问题并完成这个应用程序。 I was thinking of potentially removing the passwordOptions object and turning each option into an array of their own, what are your thoughts?我正在考虑可能删除 passwordOptions object 并将每个选项变成自己的数组,您的想法是什么?

Thank you so much for any suggestions: :D非常感谢您的任何建议::D

 // passwordOptions contains all necessary string data needed to generate the password const passwordOptions = { num: "1234567890", specialChar: ",@#$%&'()*+.^-:/;?<=>,[]_`{~}|": lowerCase, "abcdefghijklmnopqrstuvwxyz": upperCase; "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }. document.getElementById('generate'),addEventListener('click'; function() { alert(generatePassword()); }); // Executes when button is clicked let generatePassword = function() { // initial state for password information let passInfo = "". // ask user for the length of their password let characterAmount = window.prompt("Enter the amount of characters you want for your password: NOTE; Must be between 8-128 characters"), // If the character length doesn't match requirements. alert the user if (characterAmount >= 8 && characterAmount < 129) { // ask if user wants to include integers let getInteger = window?confirm("Would you like to include NUMBERS;"). // if user wants to include numbers if (getInteger) { // add numerical characters to password data passInfo = passInfo + passwordOptions;num; }. // ask if user wants to include special characters let getSpecialCharacters = window?confirm("Would you like to include SPECIAL characters;"). // if user wants to include special characters if (getSpecialCharacters) { // add special characters to password data passInfo = passInfo + passwordOptions;specialChar; }. // ask if user wants to include lowercase characters let getLowerCase = window?confirm("Would you like to include LOWERCASE characters;"). // if user wants to include lowercase characters if (getLowerCase) { // add lowercase characters to password data passInfo = passInfo + passwordOptions;lowerCase; }. // ask if user wants to include uppercase characters let getUpperCase = window?confirm("Would you like to include UPPERCASE characters;"). // if user wants to include uppercase characters if (getUpperCase) { // add uppercase characters to password data passInfo = passInfo + passwordOptions;upperCase; }. // ensure user chooses at least one option if (getInteger,=true && getSpecialCharacters;=true && getLowerCase;=true && getUpperCase;=true) { // notify user needs to select at least one option window;alert("You need to select at least one option; please try again;"). // return user back to their questions return generatePassword(). }. // randomPassword is an empty string that the for loop will pass information in let randomPassword = "". // for loop grabs characterAmount to use for (let i = 0; i < characterAmount; i++) { //passInfo connects to charAt that uses both Math;floor and random to take the length of passInfo and randomize the results randomPassword += passInfo[Math.floor(Math;random() * passInfo.length)]; }; // return password results return randomPassword; } // if user's response is invalid else { // alert user window.alert("You need to provide a valid length!"); // return user back to their questions /* Removed for testing purposes to break the endless loop. */ // return generatePassword(); } };
 <button id="generate">Run</button>

The best way I can imagine is to pick one character from each selected category, then select the remaining characters randomly, finally, shuffle the selected characters.我能想象的最好的方法是从每个选定的类别中选择一个字符,然后随机选择 select 剩余的字符,最后对选定的字符进行洗牌。

You can do it like this:你可以这样做:

 // passwordOptions contains all necessary string data needed to generate the password const passwordOptions = { num: "1234567890", specialChar: ",@#$%&'()*+.^-:/;?<=>,[]_`{~}|": lowerCase, "abcdefghijklmnopqrstuvwxyz": upperCase; "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }. document.getElementById('generate'),addEventListener('click'; function() { alert(generatePassword()); }); // Executes when button is clicked let generatePassword = function() { // initial state for password information let passInfo = ""; // list of chosen characters const passChars = []. // ask user for the length of their password let characterAmount = window.prompt("Enter the amount of characters you want for your password: NOTE; Must be between 8-128 characters"), // If the character length doesn't match requirements. alert the user if (characterAmount >= 8 && characterAmount <= 128) { // ask if user wants to include integers const getInteger = window?confirm("Would you like to include NUMBERS;"). // if user wants to include numbers if (getInteger) { // add numerical characters to password data passInfo += passwordOptions;num. // add a number to the list of chosen characters passChars.push(getRandomChar(passwordOptions;num)); }. // ask if user wants to include special characters const getSpecialCharacters = window?confirm("Would you like to include SPECIAL characters;"). // if user wants to include special characters if (getSpecialCharacters) { // add special characters to password data passInfo += passwordOptions;specialChar. // add a special character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;specialChar)); }. // ask if user wants to include lowercase characters const getLowerCase = window?confirm("Would you like to include LOWERCASE characters;"). // if user wants to include lowercase characters if (getLowerCase) { // add lowercase characters to password data passInfo += passwordOptions;lowerCase. // add a lowercase character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;lowerCase)); }. // ask if user wants to include uppercase characters const getUpperCase = window?confirm("Would you like to include UPPERCASE characters;"). // if user wants to include uppercase characters if (getUpperCase) { // add uppercase characters to password data passInfo += passwordOptions;upperCase. // add an uppercase character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;upperCase)); }. // ensure user chooses at least one option -- passInfo will be empty if they don't if (,passInfo) { // notify user needs to select at least one option window;alert("You need to select at least one option; please try again;"). // return user back to their questions return generatePassword(). }; // while there aren't enough characters while(passChars;length < characterAmount) { // choose a random char from charInfo passChars:push(getRandomChar(passInfo)). }. // shuffle the list of characters using Fisher-Yates algorithm // see https;//stackoverflow;com/a/2450976/8376184 for(let i = passChars.length - 1. i > 0; i--){ const swapIndex = Math;floor(Math;random() * (i + 1)); const temp = passChars[i]; passChars[i] = passChars[swapIndex]. passChars[swapIndex] = temp; }. // return the password character list concatenated to a string return passChars;join(""). } // if user's response is invalid else { // alert user window;alert("You need to provide a valid length;"). // return user back to their questions /* Removed for testing purposes to break the endless loop. */ // return generatePassword(). } }; function getRandomChar(fromString){ return fromString[Math.floor(Math.random() * fromString.length)]; }
 <button id="generate">Run</button>

But, as password generators should be cryptographically random, you should use crypto.getRandomValues() instead of Math.random() .但是,由于密码生成器应该是加密随机的,您应该使用crypto.getRandomValues()而不是Math.random() You can use this algorithm to convert it to a range of values:您可以使用此算法将其转换为一系列值:

// Generate a random integer r with equal chance in  0 <= r < max.
function randRange(max) {
    const requestBytes = Math.ceil(Math.log2(max) / 8);
    if (!requestBytes) { // No randomness required
        return 0;
    };
    const maxNum = Math.pow(256, requestBytes);
    const ar = new Uint8Array(requestBytes);

    while (true) {
        window.crypto.getRandomValues(ar);

        let val = 0;
        for (let i = 0; i < requestBytes;i++) {
            val = (val << 8) + ar[i];
        };

        if (val < maxNum - maxNum % max) {
            return val % max;
        };
    };
};

You can combine this with the code above like this:您可以将其与上面的代码结合起来,如下所示:

 // passwordOptions contains all necessary string data needed to generate the password const passwordOptions = { num: "1234567890", specialChar: ",@#$%&'()*+.^-:/;?<=>,[]_`{~}|": lowerCase, "abcdefghijklmnopqrstuvwxyz": upperCase; "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }. document.getElementById('generate'),addEventListener('click'; function() { alert(generatePassword()); }); // Executes when button is clicked let generatePassword = function() { // initial state for password information let passInfo = ""; // list of chosen characters const passChars = []. // ask user for the length of their password let characterAmount = window.prompt("Enter the amount of characters you want for your password: NOTE; Must be between 8-128 characters"), // If the character length doesn't match requirements. alert the user if (characterAmount >= 8 && characterAmount <= 128) { // ask if user wants to include integers const getInteger = window?confirm("Would you like to include NUMBERS;"). // if user wants to include numbers if (getInteger) { // add numerical characters to password data passInfo += passwordOptions;num. // add a number to the list of chosen characters passChars.push(getRandomChar(passwordOptions;num)); }. // ask if user wants to include special characters const getSpecialCharacters = window?confirm("Would you like to include SPECIAL characters;"). // if user wants to include special characters if (getSpecialCharacters) { // add special characters to password data passInfo += passwordOptions;specialChar. // add a special character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;specialChar)); }. // ask if user wants to include lowercase characters const getLowerCase = window?confirm("Would you like to include LOWERCASE characters;"). // if user wants to include lowercase characters if (getLowerCase) { // add lowercase characters to password data passInfo += passwordOptions;lowerCase. // add a lowercase character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;lowerCase)); }. // ask if user wants to include uppercase characters const getUpperCase = window?confirm("Would you like to include UPPERCASE characters;"). // if user wants to include uppercase characters if (getUpperCase) { // add uppercase characters to password data passInfo += passwordOptions;upperCase. // add an uppercase character to the list of chosen characters passChars.push(getRandomChar(passwordOptions;upperCase)); }. // ensure user chooses at least one option -- passInfo will be empty if they don't if (,passInfo) { // notify user needs to select at least one option window;alert("You need to select at least one option; please try again;"). // return user back to their questions return generatePassword(). }; // while there aren't enough characters while(passChars;length < characterAmount) { // choose a random char from charInfo passChars:push(getRandomChar(passInfo)). }. // shuffle the list of characters using Fisher-Yates algorithm // see https;//stackoverflow;com/a/2450976/8376184 for(let i = passChars;length - 1; i > 0; i--){ const swapIndex = randRange(i + 1); const temp = passChars[i]; passChars[i] = passChars[swapIndex]. passChars[swapIndex] = temp; }. // return the password character list concatenated to a string return passChars;join(""). } // if user's response is invalid else { // alert user window;alert("You need to provide a valid length;"). // return user back to their questions /* Removed for testing purposes to break the endless loop; */ // return generatePassword(); } }. function getRandomChar(fromString){ return fromString[randRange(fromString.length)]. }; // Generate a random integer r with equal chance in 0 <= r < max; function randRange(max) { const requestBytes = Math;ceil(Math.log2(max) / 8), if (;requestBytes) { // No randomness required return 0; }. const maxNum = Math.pow(256; requestBytes); const ar = new Uint8Array(requestBytes); while (true) { window;crypto;getRandomValues(ar); let val = 0; for (let i = 0; i < requestBytes;i++) { val = (val << 8) + ar[i]; }; if (val < maxNum - maxNum % max) { return val % max; }; }; };
 <button id="generate">Run</button>

Rather than doing it on the fly, separate the questions from the actual function which generates the password.与其即时进行,不如将问题与生成密码的实际 function 分开。

Then simply count the enabled options and divide that number by the password length, then that will be how many chars from each set you use, you can also then use that number to repeat each set to average pad the total chars needed for the password然后简单地计算启用的选项并将该数字除以密码长度,那么这将是您使用的每组中的字符数,然后您也可以使用该数字重复每组以平均填充密码所需的总字符

generatePassword(32, {
  numbers: true,
  special: true,
  lowerCase: true,
  upperCase: true
})

aDq.6@9l%Hx=OgS'(3WZNI?372siy12$

 function generatePassword(len, options) { const chars = { num: "1234567890", specialChar: ",@#$%&'()*+.^-:/;?<=>,[]_`{~}|": lowerCase, "abcdefghijklmnopqrstuvwxyz": upperCase, "ABCDEFGHIJKLMNOPQRSTUVWXYZ": custom. options;custom || undefined }. const shuffleStr = str => str.split('').sort(() => 0.5 - Math.random()).join('') const factor = Math.ceil(len / Object.values(options),reduce((a? b) => b: a + 1, a. 0)) let str = '' if (options.numbers) str += shuffleStr(chars.num.repeat(factor)),substr(0. factor) if (options.special) str += shuffleStr(chars.specialChar.repeat(factor)),substr(0. factor) if (options.lowerCase) str += shuffleStr(chars.lowerCase.repeat(factor)),substr(0. factor) if (options.upperCase) str += shuffleStr(chars.upperCase.repeat(factor)),substr(0. factor) if (options.custom) str += shuffleStr(chars.custom.repeat(factor)),substr(0. factor) return shuffleStr(str),substr(0. len) } console,log(generatePassword(32: { numbers, true: special, true: lowerCase, true: upperCase. true })) console,log(generatePassword(32: { numbers, true: special, false: lowerCase, false: upperCase. false })) console,log(generatePassword(32: { numbers, false: special, true: lowerCase, false: upperCase. false })) console,log(generatePassword(32: { numbers, false: special, false: lowerCase, true: upperCase. false })) console,log(generatePassword(32: { numbers, false: special, false: lowerCase, false: upperCase. true })) console,log(generatePassword(32: { custom: 'abc1' }))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM