generating random string with requirements in Pyth

2019-08-05 20:16发布

问题:

I'm trying to generate random passwords for the Active Directory that has the following password requirements: at least 8 characters, at least one special character, at least one digit, at least one lowercase and at least one uppercase.

With the following code I'm able to generate a random password and check whether it contains a special character. New password is generated until a special character is found.

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

The problem with the following is that it's only checking for the special character and generating a new password might get rid of the other requirements assuming they existed. How could I implement the AD password requirements efficiently? Thanks for any help.

回答1:

You could generate a matching password to begin with, by first picking a special char and a digit (and one lower- and one uppercase letter in the same manner), filling up with anything, and shuffling the order in the end:

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)


回答2:

Test for all conditions in your while test. It is easier to delegate testing for valid passwords to a function:

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


回答3:

Use sets and intersection to enforce constraints...

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


回答4:

I like Ulrich's answer better. He beat me to it.

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:

You could implement the requirements one by one..

  • at least 8 characters
  • at least one special character
  • at least one digit
  • at least one lowercase and
  • at least one uppercase.

so before you do anything else create a string that consists of 1 special character randomly chosen. 1 digit character randomly chosen. 1 lowercase character randomly chosen. and 1 uppercase character randomly chosen. thats 4 characters in total, the remaining characters can be randomly chosen, length must be larger than 8.

all generated passwords will no be valid, so no need to check for that..

now you could complain that the passwords will all have the same predictable pattern: special, digit, lowercase, uppercase, randomized stuff..

so we shuffle it..

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


标签: python random