阅读控制台输入很难,您需要处理特殊的按键,如Ctrl,Alt,光标键和Backspace/Delete。在某些键盘布局上,如Swedish甚至需要使用Ctrl键输入直接存在于美式键盘上的键。我相信试图使用“低级”Console.ReadKey(true)
来处理这个问题非常困难,所以最简单和最可靠的方法就是在使用一点WINAPI输入密码期间禁用“控制台输入回显”。
以下示例基于回答Read a password from std::cin问题。
private enum StdHandle
{
Input = -10,
Output = -11,
Error = -12,
}
private enum ConsoleMode
{
ENABLE_ECHO_INPUT = 4
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(StdHandle nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetConsoleMode(IntPtr hConsoleHandle, int dwMode);
public static string ReadPassword()
{
IntPtr stdInputHandle = GetStdHandle(StdHandle.Input);
if (stdInputHandle == IntPtr.Zero)
{
throw new InvalidOperationException("No console input");
}
int previousConsoleMode;
if (!GetConsoleMode(stdInputHandle , out previousConsoleMode))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not get console mode.");
}
// disable console input echo
if (!SetConsoleMode(stdInputHandle , previousConsoleMode & ~(int)ConsoleMode.ENABLE_ECHO_INPUT))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not disable console input echo.");
}
// just read the password using standard Console.ReadLine()
string password = Console.ReadLine();
// reset console mode to previous
if (!SetConsoleMode(stdInputHandle , previousConsoleMode))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not reset console mode.");
}
return password;
}
我建议你不要回显任何东西回控制台,因为这会暴露密码的长度。 – 2012-08-15 20:41:45
@RayCheng - 足够公平,但很少有用户界面(除了某些Unix系统上)完全没有回应。为了与其他应用和网站保持一致的用户体验,显示*字符可能是最好的。 – 2014-02-19 14:02:13
@StephenHolt我相当确定每一个我遇到过的基于终端的密码输入都选择不向终端回应。鉴于安全性的好处以及这是Unix世界中众所周知的惯例,我个人认为什么都没有是正确的选择,除非您认为您的用户群可能不熟悉终端的使用(在这种情况下无论如何,最好使用GUI)。 – Ajedi32 2017-01-03 16:00:45