Python:使用带有argparse的getpass

时间:2015-01-13 11:58:44

标签: python passwords arguments prompt

我环顾四周,但找不到任何东西。

基本上我想知道是否可以将getpass.getpass()与argparse一起使用。

目前我有以下作为解决方法,我只是想知道是否有更好的方法:

import argparse
import getpass

parser = argparse.ArgumentParser(description="Some description")
parser.add_argument('-p', metavar="password", default="foobarblah123", help="password for user (default to prompt user)")
...
parsed_args = parser.parse_args()
args = vars(parsed_args)
user_pass = args['p']
if user_pass == "foobarblah123":
  user_pass = getpass.getpass()

我很确定这不是处理此问题的最佳方法,但是,需要为密码设置命令行选项...最佳做法与否。

感谢。

6 个答案:

答案 0 :(得分:13)

我想我可能找到了一个更好的方法来做到这一点。如何使用这样的自定义Action:

import argparse
import getpass

class PasswordPromptAction(argparse.Action):
    def __init__(self,
             option_strings,
             dest=None,
             nargs=0,
             default=None,
             required=False,
             type=None,
             metavar=None,
             help=None):
        super(PasswordPromptAction, self).__init__(
             option_strings=option_strings,
             dest=dest,
             nargs=nargs,
             default=default,
             required=required,
             metavar=metavar,
             type=type,
             help=help)

    def __call__(self, parser, args, values, option_string=None):
        password = getpass.getpass()
        setattr(args, self.dest, password)

parser.add_argument('-u', dest='user', type=str, required=True)
parser.add_argument('-p', dest='password', action=PasswordPromptAction, type=str, required=True)

args = parser.parse_args()

答案 1 :(得分:6)

环顾四周,找不到足够的解决方案。这就是我想出来的。

from argparse import ArgumentParser
from getpass import getpass

def main():
    parser = ArgumentParser(description="arg parser hidden password input.")
    parser.add_argument('-sp', '--secure_password', action='store_true', dest='password', 
                        help='hidden password prompt')
    args=parser.parse_args()

    if args.password:
        password = getpass()

    print(password)

if __name__ == "__main__":
    main()

显然你想删除print(password),这只是为了验证它是否有效而添加。

答案 2 :(得分:5)

以下是我提出的用于提示密码非常小(Python 3代码)的内容:

import argparse
import getpass


class Password:

    DEFAULT = 'Prompt if not specified'

    def __init__(self, value):
        if value == self.DEFAULT:
            value = getpass.getpass('LDAP Password: ')
        self.value = value

    def __str__(self):
        return self.value


parser = argparse.ArgumentParser(
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-u', '--username', help='Specify username',
    default=getpass.getuser())
parser.add_argument('-p', '--password', type=Password, help='Specify password',
    default=Password.DEFAULT)
args = parser.parse_args()

print(args.username, args.password)

用法示例:

$ python ~/Desktop/example.py -h
usage: example.py [-h] [-u USERNAME] [-p PASSWORD]

optional arguments:
  -h, --help            show this help message and exit
  -u USERNAME, --username USERNAME
                        Specify username (default: gavinr)
  -p PASSWORD, --password PASSWORD
                        Specify password (default: Prompt if not specified)

$ python ~/Desktop/example.py -p foo
gavinr foo

$ python ~/Desktop/example.py 
LDAP Password: 
gavinr foo

答案 3 :(得分:1)

基于Rares Musina的答案,我注意到一个缺点: 在命令行上提交密码后,提示将不断出现。然后在通过提示提供密码时,argparse会将命令行上已经提供的密码视为另一个参数(很可能不存在)。

在理想情况下,这是预期的行为:

  • 在命令行上未提供任何值时提示输入密码
  • 在命令行上给定值时不提示

两种情况都应接受。理想情况下,第二种情况应该发出安全警告。

nargs设置为'?'时,它期望参数为零或一个。这使得它可以选择通过命令行提供密码。

因此将“ add_argument”更改为:

arg_parser.add_argument("-p", "--password", type=str, action=PasswordPromptAction, nargs='?')

PasswordPromptAction应该进行区分。 “值”参数包含在命令行上给出的值(如果给出了值):

class PasswordPromptAction(argparse.Action):
    def __call__(self, parser, args, values, option_string=None):
        # If no value is given on the commandline prompt for password.
        if values:
            # Ideally a security warning could be generated here.
            setattr(args, self.dest, values)
        else:
            setattr(args, self.dest, getpass.getpass())

现在支持以下用法:

python program.py -p
python program.py -p p@ssw0rd

答案 4 :(得分:1)

如果未在命令中指定密码,则将使用getpass()提示。不错,因为它支持自动脚本和带有隐藏密码的手动使用。

import argparse
from getpass import getpass

parser = ArgumentParser(description="specify or prompt for a hidden password.")
parser.add_argument('-p', '--password', required=False, type=str)
args = parser.parse_args()

if not args.password: 
    args.password = getpass()

答案 5 :(得分:0)

我喜欢这种解决方案,因为用户可以同时通过两种方式:

  

$> python program.py登录 -u user1 -p pass1

或仅一个:

  

$> python program.py登录 -u user1

或任何

  

$> python program.py登录

如果未通过param传递用户或密码,则以交互方式请求。

import argparse
import getpass

def parse_args():
    parser = argparse.ArgumentParser(description="command line client")
    subparser = parser.add_subparsers(dest='command', metavar='command')
    subparser.required = True
    parser.set_defaults(funct=argparser_handler)

    # Login
    sub_parser = subparser.add_parser("login", help="Login with email and password")
    sub_parser.add_argument('-u', dest='user', help='user.  If this argument is not passed it will be requested.')
    sub_parser.add_argument('-p', dest='password', help='password.  If this argument is not passed it will be requested.')

    args = parser.parse_args()
    args.funct(args)

def argparser_handler(args):
    if (args.command == 'login'):
        login(args.user, args.password)


def login(user, password):
    if not user:
        user = input("User:") 
    if not password:
        password = getpass.getpass()    
    print("user:", user)
    print("password:", password)


def main():
    pass

if __name__ == '__main__':
    parse_args()
    main()