1

我有这个 javascript 密码生成功能。现在我正在丢弃不符合所选规范的密码。例如,如果密码不包含数字,我将其丢弃并生成一个新的,其中包含一个数字。然而,这似乎不是有效的性能虎钳,至少对我来说不是。

有没有更好的方法来实现对生成的密码中特定字符的强制?

另外我打算添加,以便可以强制密码包含特殊字符。如果我以当前方式执行此操作,我将不得不使用一些正则表达式来检查密码是否包含特殊字符,如果不包含特殊字符,则将其丢弃(再次对我来说似乎不是很有效)。

function generatePassword(length, charset, nosimilar) {
    // default parameters
    length = (typeof length === "undefined") ? 8 : length;
    charset = (typeof charset === "undefined") ? 'abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789' : charset;
    nosimilar = (typeof similar === "undefined") ? true : nosimilar;

    var gen;
    retVal = "";
    for (var i = 0, n = charset.length; i < length; ++i) {
        gen = charset.charAt(Math.floor(Math.random() * n))
        if ( (retVal.charAt( retVal.length-1 ) == gen) && (nosimilar)) {
            retVal = retVal.substring(0, retVal.length - 1)
            retVal += charset.charAt(Math.floor(Math.random() * n))
            console.log('Generated character same as the last one. Trunkated and regenerated.');
        }
        retVal += gen;
    }

    // if charset contains numbers make sure we get atleast one number
    if ( (retVal.match(/\d+/g) == null) && (charset.match(/\d+/g) != null)) {
    console.log('Password generated but no numbers found. Regenerating.');
    generatePassword(length, charset, nosimilar);
    }

    return retVal;
}

if ($("#chLetters").prop('checked')) charset += 'abcdefghjknpqrstuvwxyz';
if ($("#chNumbers").prop('checked')) charset += '123456789';
if ($("#chMixedCase").prop('checked')) charset += 'ABCDEFGHJKLMNPQRSTUVWXYZ';
if ($("#chSpecial").prop('checked')) charset += '!@$%&?+*-_';

$("#passgen").text(generatePassword($("#maxLength").val(), charset, $("#chNoSimilar").prop('checked')));
4

3 回答 3

1

如果您的密码长度为 n 个字符,并且要求它至少包含一个字母、一个数字和一个特殊字符,则意味着每个密码将包含 1 到 n-2 个字符。例如(简化):

function generatePassword( length ) {
    var letters = 'abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ',
        special = '{}()#%&',
        characters = [],
        amountOfLetters = Math.floor( Math.random() * ( length - 2 ) ) + 1,
        amountOfNumbers = Math.floor( Math.random() * ( length - 1 - amountOfLetters ) ) + 1,
        amountOfSpecial = length - ( amountOfLetters + amountOfNumbers );

    // pick letters
    for (var i = 0, n = letters.length; i < amountOfLetters; ++i) {
        characters.push( letters.charAt( Math.floor( Math.random() * n ) ) );
    }

    // pick numbers
    for ( i = 0; i < amountOfNumbers; ++i) {
        characters.push( ''+( Math.floor( Math.random() * 9 ) + 1 ) );
    }

    // pick special characters
    for ( i = 0, n = special.length; i < amountOfSpecial; ++i) {
        characters.push( special.charAt( Math.floor( Math.random() * n ) ) );
    }

    // sort the array and concatenate elements into a string
    return characters.sort( function( a, b ) {
        return Math.random() - 0.5;
    } ).join( '' );
}

演示:http: //jsfiddle.net/gGwyM/

该函数选择 1 到 n-2 个字母,然后是 1 到 nL-1 个数字(其中 L 是字母的数量),其余的是特殊字符。这保证了密码至少包含每个组中的一个字符。

(请注意,您应该使用比我这里更好的函数来随机化数组,请参阅例如How to randomize (shuffle) a JavaScript array?

于 2013-05-04T09:36:41.923 回答
0

你可以使用这样的东西。使用此方法允许您创建多个密钥集,并且通过使用简单的选项属性,您可以将这些密钥集切换进和退出密码生成,以及设置长度甚至选择生成十六进制密码。

function isObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}

function assign(target, source) {
  for (var prop in source) {
    if (source.hasOwnProperty(prop)) {
      target[prop] = source[prop];
    }
  }

  return target;
}

function shuffle(obj) {
  var i = obj.length;
  var rnd, tmp;

  while (i) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    tmp = obj[i];
    obj[i] = obj[rnd];
    obj[rnd] = tmp;
  }

  return obj;
}

function generatePassword(options) {
  var opts = isObject(options) ? assign({}, options) : {};
  var keyspace = '';
  if (opts.hex) {
    keyspace = '0123456789abcdef';
    if (opts.uppercase) {
      keyspace = keyspace.toUpperCase();
    }
  } else {
    if (opts.alpha) {
      keyspace += 'abcdefghijklmnopqrstuvwxyz';
    }

    if (opts.uppercase) {
      keyspace += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    }

    if (opts.numeric) {
      keyspace += '0123456789';
    }

    if (opts.punctuation) {
      keyspace += "`!\"?$?%^&*()_-+={[}]:;@'~#|\\<,>.?/";
    }
  }

  if (keyspace.length - 1 < 0) {
    return '';
  }

  opts.size = opts.size >>> 0 || 16;
  if (opts.size < 5) {
    opts.size = 5;
  } else if (opts.size > 100) {
    opts.size = 100;
  }

  return shuffle(keyspace.split('')).join('').slice(0, opts.size);
}

var password = generatePassword({
  alpha: true,
  uppercase: true,
  numeric: true,
  punctuation: true
});

console.log(password);

其他选项是十六进制生成的长度大小

您可以修改它以获取您想要使用的特殊字符的字符串。

更新:这是一个更复杂的示例,它强制执行每种类型的所选字符的数量,并且与上面的简单示例类似。

function isObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}

function assign(target, source) {
  for (var prop in source) {
    if (source.hasOwnProperty(prop)) {
      target[prop] = source[prop];
    }
  }

  return target;
}

function shuffle(obj) {
  var i = obj.length;
  var rnd, tmp;

  while (i) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    tmp = obj[i];
    obj[i] = obj[rnd];
    obj[rnd] = tmp;
  }

  return obj;
}

function getXChars(string, number) {
  var str = typeof string === 'string' ? string : '';
  var num = typeof number === 'number' && number > 0 ? number : 0;
  var array = [];
  var i = str.length;
  var rnd;

  while (i && array.length < num) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    array.push(str.charAt(rnd));
  }

  return array;
}

function generatePassword(opts) {
  var opts = isObject(opts) ? assign({}, opts) : {};
  var keyspace = '';
  var result = [];
  var i = 0;
  var tmp;

  if (typeof opts.hex === 'number' && opts.hex > 0) {
    i += opts.hex;
    keyspace = '0123456789abcdef';
    if (opts.uppercase === true) {
      keyspace = keyspace.toUpperCase();
    }

    result = result.concat(getXChars(keyspace, opts.hex));
  } else {
    if (typeof opts.alpha === 'number' && opts.alpha > 0) {
      i += opts.alpha;
      tmp = 'abcdefghijklmnopqrstuvwxyz';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.alpha));
    }

    if (typeof opts.uppercase === 'number' && opts.uppercase > 0) {
      i += opts.uppercase;
      tmp = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.uppercase));
    }

    if (typeof opts.numeric === 'number' && opts.numeric > 0) {
      i += opts.numeric;
      tmp = '0123456789';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.numeric));
    }

    if (typeof opts.punctuation === 'number' && opts.punctuation > 0) {
      i += opts.punctuation;
      tmp = "`!\"?$?%^&*()_-+={[}]:;@'~#|\\<,>.?/";
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.punctuation));
    }
  }

  if (keyspace.length === 0) {
    return keyspace;
  }

  opts.size = opts.size >>> 0 || 16;
  if (opts.size < 5) {
    opts.size = 5;
  } else if (opts.size > 100) {
    opts.size = 100;
  }

  result = result.concat(getXChars(keyspace, opts.size - i));

  return shuffle(result).join('');
}

var password = generatePassword({
  alpha: 1,
  uppercase: 1,
  numeric: 1,
  punctuation: 1
});

console.log(password);

更新:正如这里所承诺的,它可能是Math.random的替代品。如果window.crypto.getRandomValues可用,那么它将使用它,否则它会回退到 Math.random。

function random() {
  if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
    console.log('Using crypto');
    var array = new Uint32Array(1);
    window.crypto.getRandomValues(array);
    return array[0] / (Math.pow(2, 32) + 1);
  }

  console.log('Using random');
  return Math.random();
}

console.log(random());

于 2013-05-04T09:29:14.157 回答
0

我认为您需要根据数组的要求从不同的数组中挑选字符。这是我的解决方案:

var alphas = "abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
var specials = "!#$%&/()=`";
var numbers = "1234567890";

var requiredSpecials = 1;
var requiredNumbers = 2;

function pickRandom(str, count){
    var remaining = str;
    var result = "";
    while (remaining.length > 0 && count > 0){
        // pick random char from remaining
        var char = remaining.charAt(Math.floor(Math.random() *remaining.length));

        // remove char from remaining. (Just replace with empty string)
        remaining = remaining.replace(char, "");

        // add char to result
        result += char;

        // decrement count
        count -= 1;
    }

    return result;
}

function shuffleString(str){
    var arr = str.split(''); // Convert to array
    arr.sort(function(){ // Sort by random
        return 0.5-Math.random()
    })
    return arr.join(''); // Join back to string
}

function generate(length){
    var specialCount = requiredSpecials;
    var numberCount = requiredNumbers;
    var alphaCount = length - specialCount - numberCount;

    var tmp = pickRandom(alphas, alphaCount) + pickRandom(specials, specialCount) + pickRandom(numbers, numberCount);

    // Shuffle and return
    return shuffleString(tmp);
}

alert(generate(9))

你也可以在jsFiddle玩它

于 2013-05-04T09:48:33.350 回答