如何在Perl中提示输入密码时不在终端显示密码?

15
如何在不显示终端中的密码的情况下提示用户输入密码?有一个类似的问题如何使用Perl输入密码并用'*'替换字符?,但回答似乎已过时或失效。
我正在寻找这个问题的答案,并不满意后面结果页面上与其他相关问题有关的答案。
此外,perlfaq8 有一个不完整的示例(哦,谁曾经维护它;)。
 use Term::ReadKey;
 ReadMode('noecho');
 my $password = ReadLine(0);

如果您不重置终端,那么就没有其他回显了!哎呀!

我还在寻找新的答案或模块,可以提供给想要做这件事的人。


这几年有什么变化吗?对我来说(截至09/2020),这个代码可以使用LWP::UserAgent:print "请输入密码:"; ReadMode('noecho'); my $pass=ReadLine(0); chomp($pass); $request->authorization_basic('用户名', $pass); - MacMartin
LWP与此无关。否则,您将拥有相同的代码。 - brian d foy
正确。我的意思是,我在LWP的上下文中使用了perlfaq8中的那些行(这可能是无用的信息)- 在那个上下文中它完美地工作。没有问题,也不需要重置终端。(也许你4年前看到的问题已经解决了?不知道) - MacMartin
4个回答

12
为了使用Term::ReadKey,请按照以下步骤进行操作:
sub prompt_for_password {
    require Term::ReadKey;

    # Tell the terminal not to show the typed chars
    Term::ReadKey::ReadMode('noecho');

    print "Type in your secret password: ";
    my $password = Term::ReadKey::ReadLine(0);

    # Rest the terminal to what it was previously doing
    Term::ReadKey::ReadMode('restore');

    # The one you typed didn't echo!
    print "\n";

    # get rid of that pesky line ending (and works on Windows)
    $password =~ s/\R\z//;

    # say "Password was <$password>"; # check what you are doing :)

    return $password;
}

这可以通过决定修剪前导或尾随空格以及如何从末尾删除某些内容来改进。在Windows上,“chomp”可能无法正常工作。 - brian d foy
使用上述程序,chomp 在 Windows 上能够正常工作。关于 IO::Prompter 的问题,请参见 RT#118255 - Sinan Ünür
1
如果用户在密码提示处按下Ctrl-C,此解决方案不会将终端恢复到先前的(echo)状态。为了解决这个问题,必须设置$SIG{INT} = sub { ... };处理程序。 - pts
这是一个社区维基,所以您可以编辑答案 :) - brian d foy

2

你也可以使用IO::Prompter

$ perl -MIO::Prompter -wE '$pass = prompt("Password: ", -echo => "*"); $pass =~ s/\R\z//; say $pass'

对于仅仅询问密码来说,这可能有点过头了,但如果你需要引导其他类型的用户输入,它是很有用的。请注意,为了使密码屏蔽功能正常工作,您确实需要 Term::ReadKey 模块。不幸的是,该模块在构建时没有提醒您关于此问题。如果上述一行代码生成以下警告,表示您处于这种情况:

警告:下一个输入将以明文显示

prompt() 子程序被调用时带有 -echo 标志,但 Term::ReadKey 模块未安装以实现此功能。输入将按正常方式进行,但发出此警告是为了确保用户不会输入一些期望保持隐藏的秘密内容。

我无法理解警告消息与其解释所给的含义之间的联系,但没办法,就这样吧。

请注意,在 Windows 上,该模块在输入字符串的末尾留下一个 CR,而 chomp 不会将其删除(因为它正在寻找一个 CRLF 序列)。这就是为什么我在上面的示例中使用了 \R。请参见 RT #118255

0

网上有很多建议包含system("stty -echo"),但这在Win32上不起作用(仅限Unix),而使用该方法的实际强大解决方案很快变得复杂(超过30行,具有可移植性问题):1.处理Ctrl-C是一团糟(需要$SIG{INT} = ...或更多的stty标志),2.很难获取TTY设备文件句柄并将其传递给stty(使用shell重定向或一些Perl open(...)魔法),以防stdin、stdout或stderr被重定向。


0

Term::ReadPassword::Win32 可在 Win32 和 Unix 上使用(尽管其名称表明不是这样)。在 Unix 上,它使用 Term::ReadPassword

use strict;
use warnings;
use Term::ReadPassword::Win32 qw(read_password);
my $input = read_password("Password: ");
say $input;

很遗憾,我无法找到一个短小的解决方案,可以使用标准的Perl模块(即不需要安装)。如果您无法从CPAN安装,请考虑从上面的模块中复制粘贴代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接