【问题标题】:generating random string with requirements in Python 3在 Python 3 中生成具有要求的随机字符串
【发布时间】:2015-11-18 08:15:53
【问题描述】:

我正在尝试为具有以下密码要求的 Active Directory 生成随机密码:至少 8 个字符、至少一个特殊字符、至少一个数字、至少一个小写字母和至少一个大写字母。

通过以下代码,我可以生成一个随机密码并检查它是否包含特殊字符。在找到特殊字符之前会生成新密码。

special_char = "!@%/()=?+.-"

password_string = "".join([random.choice(string.ascii_lowercase + string.ascii_digits + string.ascii_uppercase + special_char) for n in range(8)])

while any(c in password_string for c in special_char) is not True:
    password_string = "".join([random.choice(string.ascii_lowercase + string.ascii_digits + string.ascii_uppercase + special_char) for n in range(8)])

以下问题是它只检查特殊字符并生成新密码可能会摆脱假设存在的其他要求。如何有效地实施 AD 密码要求?感谢您的帮助。

【问题讨论】:

  • 另外说明:不要使用(boolean expr) is not True;使用not (boolean expr)

标签: python random


【解决方案1】:

您可以首先生成一个匹配的密码,首先选择一个特殊的字符和一个数字(以及一个小写和一个大写字母,以相同的方式),填写任何内容,最后打乱顺序:

pwlist = ([random.choice(special_char),
           random.choice(string.ascii_digits),
           random.choice(string.ascii_lowercase),
           random.choice(string.ascii_uppercase),
          ]  
         + [random.choice(string.ascii_lowercase
                          + string.ascii_uppercase
                          + special_char
                          + string.ascii_digits) for i in range(4)])
random.shuffle(pwlist)
pw = ''.join(pwlist)

【讨论】:

  • 很好的解决方案....我喜欢它。最终密码中每个字符类的预期字符数可能与 OPs 算法不同……但我不认为这是一个限制。
  • @Jug:是的,这“感觉是真的”,这应该与“丢弃直到你做对”具有相同的随机性,但这并不是很明显。
【解决方案2】:

使用集合和交集来强制约束...

import string
import random

special_char = "!@%/()=?+.-"
set_lower = set(string.ascii_lowercase)
set_upper = set(string.ascii_uppercase)
set_digits = set(string.digits)
set_sp = set(special_char)

all_chars = string.ascii_lowercase + \
    string.digits + \
    string.ascii_uppercase + \
    special_char

password_string = "".join([random.choice(all_chars) for n in range(8)])

def isOK(pw):
    pw = set(pw)
    for x in (set_lower, set_upper, set_digits, set_sp):
        if len(pw.intersection(x)) == 0:
            return False
    return True

while not isOK(password_string):
    password_string = "".join([random.choice(all_chars) for n in range(8)])

print password_string

【讨论】:

  • string.lowercasestring.uppercase 因地区而异。我会坚持使用string.ascii_letters(其中包含string.ascii_lowercasestring.ascii_uppercase)。
  • 这个解决方案对于 while 循环的每次迭代都有一个不幸的命中和未命中方面。
  • @DevPlayer 同意...这仅修复了操作方法,同时保持生成的密码空间相同。 Ulrich 的答案具有副作用,即它根据 op 提供的算法改变了不同密码的概率。变化很小,但它就在那里。
  • @Jug 我怀疑但不确定,如果从 Ulrich 解决方案的内部列表理解中删除特殊字符,则概率将与 OP 相同。虽然我觉得(我知道不是很不切实际)这实际上会使密码更难破解。另外我怀疑我在底部发布的解决方案与 Ulrich 的概率差异相同。
  • @DevPlayer 仔细检查...我确实看到字符的概率分布是相同的。所以乌尔里希和你的答案在这方面确实是优越的。干杯。
【解决方案3】:

测试while 测试中的所有条件。将有效密码的测试委托给函数更容易:

special_char = "!@%/()=?+.-"
password_characters = string.ascii_letters + string.ascii_digits + special_char

def is_valid(password):
    if len(password) < 8:
        return False
    if not any(c in password for c in special_char):
        return False
    if not any(c.isdigit() for c in password):
        return False
    if not any(c.islower() for c in password):
        return False
    if not any(c.isupper() for c in password):
        return False
    return True

password_string = ''
while not is_valid(password_string):
    password_string = "".join([random.choice(password_characters)
                               for n in range(8)])

【讨论】:

  • 这个解决方案有可能会浪费大量时间,直到满足所有要求。
  • @DevPlayer:理论上,循环可以永远运行下去。在实践中,你永远不会注意到。但是,是的,选择一个随机数字、随机特殊字符、随机小写和随机大写字母,用所有有效字符填充它并改组结果将避免理论上的永久循环。
【解决方案4】:

我更喜欢 Ulrich 的回答。他打败了我。

import string
import random
string_specials = '!@%/()=?+.-'
string_pool = string_specials + string.ascii_letters + string.digits
pre_password = [
    random.choice(string_specials),
    random.choice(string.ascii_uppercase),
    random.choice(string.ascii_lowercase),
    random.choice(string.digits),
    random.choice(string_pool),
    random.choice(string_pool),
    random.choice(string_pool),
    random.choice(string_pool)]
scrambled = []
while pre_password:
    scrambled.append(pre_password.pop(random.randint(0, len(pre_password)-1)))
password = ''.join(scrambled)

【讨论】:

    【解决方案5】:

    你可以一一实现需求..

    • 至少 8 个字符
    • 至少一个特殊字符
    • 至少一位数
    • 至少一个小写和
    • 至少一个大写字母。

    所以在你做任何其他事情之前 创建一个包含以下内容的字符串 随机选择1个特殊字符。 随机选择 1 个数字字符。 随机选择 1 个小写字符。 和随机选择的 1 个大写字符。 总共4个字符,其余字符可以随机选择,长度必须大于8。

    所有生成的密码都将无效,因此无需检查..

    现在您可以抱怨密码都具有相同的可预测模式: 特殊,数字,小写,大写,随机的东西..

    所以我们洗牌..

    import string
    SpecialChars = "!@%/()=?+.-"
    
    password = ""
    
    import random
    password += random.choice(string.ascii_uppercase)
    password += random.choice(string.ascii_lowercase)
    password += random.choice(string.digits)
    password += random.choice(SpecialChars)
    
    i = random.randint(4, 8)
    
    for i in range(0,i):
        password += random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits+ SpecialChars)
    
    password = ''.join(random.sample(password,len(password)))
    
    print password
    

    【讨论】:

    • 在这里使用string.ascii_digits 有什么问题?对于范围内的随机整数,只需使用random.randint(4, 8)
    猜你喜欢
    • 2012-03-31
    • 2018-07-03
    • 2014-03-07
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    相关资源
    最近更新 更多