密码屏蔽控制台应用程序

我尝试了下面的代码…

string pass = ""; Console.Write("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { Console.Write("\b"); } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 

但是这种方式在input密码时退格function不起作用。 任何build议?

Console.Write("\b \b"); 将从屏幕上删除星号字符,但是你的else块中没有任何代码从你的passstringvariables中删除以前input的字符。

下面是相关的代码部分( if..else部分)应该做你所需要的:

 // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter) { pass += key.KeyChar; Console.Write("*"); } else { if (key.Key == ConsoleKey.Backspace && pass.Length > 0) { pass = pass.Substring(0, (pass.Length - 1)); Console.Write("\b \b"); } } 

为此,您应该使用System.Security.SecureString

 public SecureString GetPassword() { var pwd = new SecureString(); while (true) { ConsoleKeyInfo i = Console.ReadKey(true); if (i.Key == ConsoleKey.Enter) { break; } else if (i.Key == ConsoleKey.Backspace) { if (pwd.Length > 0) { pwd.RemoveAt(pwd.Length - 1); Console.Write("\b \b"); } } else { pwd.AppendChar(i.KeyChar); Console.Write("*"); } } return pwd; } 

完整的解决scheme,香草C#.net 3.5+

剪切和粘贴:)

  using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleReadPasswords { class Program { static void Main(string[] args) { Console.Write("Password:"); string password = Orb.App.Console.ReadPassword(); Console.WriteLine("Sorry - I just can't keep a secret!"); Console.WriteLine("Your password was:\n<Password>{0}</Password>", password); Console.ReadLine(); } } } namespace Orb.App { /// <summary> /// Adds some nice help to the console. Static extension methods don't exist (probably for a good reason) so the next best thing is congruent naming. /// </summary> static public class Console { /// <summary> /// Like System.Console.ReadLine(), only with a mask. /// </summary> /// <param name="mask">a <c>char</c> representing your choice of console mask</param> /// <returns>the string the user typed in </returns> public static string ReadPassword(char mask) { const int ENTER = 13, BACKSP = 8, CTRLBACKSP = 127; int[] FILTERED = { 0, 27, 9, 10 /*, 32 space, if you care */ }; // const var pass = new Stack<char>(); char chr = (char)0; while ((chr = System.Console.ReadKey(true).KeyChar) != ENTER) { if (chr == BACKSP) { if (pass.Count > 0) { System.Console.Write("\b \b"); pass.Pop(); } } else if (chr == CTRLBACKSP) { while (pass.Count > 0) { System.Console.Write("\b \b"); pass.Pop(); } } else if (FILTERED.Count(x => chr == x) > 0) { } else { pass.Push((char)chr); System.Console.Write(mask); } } System.Console.WriteLine(); return new string(pass.Reverse().ToArray()); } /// <summary> /// Like System.Console.ReadLine(), only with a mask. /// </summary> /// <returns>the string the user typed in </returns> public static string ReadPassword() { return Orb.App.Console.ReadPassword('*'); } } } 

矿忽略控制字符并处理换行:

 public static string ReadLineMasked(char mask = '*') { var sb = new StringBuilder(); ConsoleKeyInfo keyInfo; while ((keyInfo = Console.ReadKey(true)).Key != ConsoleKey.Enter) { if (!char.IsControl(keyInfo.KeyChar)) { sb.Append(keyInfo.KeyChar); Console.Write(mask); } else if (keyInfo.Key == ConsoleKey.Backspace && sb.Length > 0) { sb.Remove(sb.Length - 1, 1); if (Console.CursorLeft == 0) { Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); Console.Write(' '); Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); } else Console.Write("\b \b"); } } Console.WriteLine(); return sb.ToString(); } 

将最重要的答案以及评论中的build议修改为使用SecureString而不是String,对所有控制键进行testing,并且在密码长度为0时不会出现错误或者写入额外的“*”我的解决scheme是:

 public static SecureString getPasswordFromConsole(String displayMessage) { SecureString pass = new SecureString(); Console.Write(displayMessage); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (!char.IsControl(key.KeyChar)) { pass.AppendChar(key.KeyChar); Console.Write("*"); } else { if (key.Key == ConsoleKey.Backspace && pass.Length > 0) { pass.RemoveAt(pass.Length - 1); Console.Write("\b \b"); } } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); return pass; } 

阅读控制台input是困难的,你需要处理特殊的键,如Ctrl,Alt,光标键和Backspace / Delete。 在某些键盘布局上,如瑞典式 Ctrl甚至需要input美国键盘上直接存在的键。 我相信试图使用“低级别” Console.ReadKey(true)来处理这个问题非常困难,所以最简单和最可靠的方法就是在使用一点WINAPIinput密码期间禁用“console input echo” 。

下面的示例是基于从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; } 

我在shermy的香草C#3.5 .NET解决scheme中发现了一个错误,否则这个错误很有魅力。 我也join了DamianLeszczyński – Vash的SecureString的想法,但是如果你愿意,你可以使用一个普通的string。

错误:如果在密码提示期间按退格键,并且密码的当前长度为0,则密码掩码中将错误地插入一个星号。 要修复此错误,请修改以下方法。

  public static string ReadPassword(char mask) { const int ENTER = 13, BACKSP = 8, CTRLBACKSP = 127; int[] FILTERED = { 0, 27, 9, 10 /*, 32 space, if you care */ }; // const SecureString securePass = new SecureString(); char chr = (char)0; while ((chr = System.Console.ReadKey(true).KeyChar) != ENTER) { if (((chr == BACKSP) || (chr == CTRLBACKSP)) && (securePass.Length > 0)) { System.Console.Write("\b \b"); securePass.RemoveAt(securePass.Length - 1); } // Don't append * when length is 0 and backspace is selected else if (((chr == BACKSP) || (chr == CTRLBACKSP)) && (securePass.Length == 0)) { } // Don't append when a filtered char is detected else if (FILTERED.Count(x => chr == x) > 0) { } // Append and write * mask else { securePass.AppendChar(chr); System.Console.Write(mask); } } System.Console.WriteLine(); IntPtr ptr = new IntPtr(); ptr = Marshal.SecureStringToBSTR(securePass); string plainPass = Marshal.PtrToStringBSTR(ptr); Marshal.ZeroFreeBSTR(ptr); return plainPass; } 

您可以将您的密钥附加到累积的链接列表中。

收到退格键时,从列表中删除最后一个键。

当您收到input键时,将您的列表折叠成一个string并完成剩下的工作。

我对退格进行了一些更改

  string pass = ""; Console.Write("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // Backspace Should Not Work if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { pass = pass.Remove(pass.Length - 1); Console.Write("\b \b"); } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 

我花了太多时间尝试input密码后才更新了Ronnie的版本,结果发现我有我的大写locking!

使用这个版本, _CapsLockMessage的消息将在input区域的末尾“浮动”,并以红色显示。

这个版本需要更多的代码,并需要一个轮询循环。 在我的电脑CPU使用率约3%到4%,但总是可以添加一个小的Sleep()值,以减lessCPU使用情况,如果需要的话。

  private const string _CapsLockMessage = " CAPS LOCK"; /// <summary> /// Like System.Console.ReadLine(), only with a mask. /// </summary> /// <param name="mask">a <c>char</c> representing your choice of console mask</param> /// <returns>the string the user typed in</returns> public static string ReadLineMasked(char mask = '*') { // Taken from http://stackoverflow.com/a/19770778/486660 var consoleLine = new StringBuilder(); ConsoleKeyInfo keyInfo; bool isDone; bool isAlreadyLocked; bool isCapsLockOn; int cursorLeft; int cursorTop; ConsoleColor originalForegroundColor; isDone = false; isAlreadyLocked = Console.CapsLock; while (isDone == false) { isCapsLockOn = Console.CapsLock; if (isCapsLockOn != isAlreadyLocked) { if (isCapsLockOn) { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; originalForegroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.Write("{0}", _CapsLockMessage); Console.SetCursorPosition(cursorLeft, cursorTop); Console.ForegroundColor = originalForegroundColor; } else { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; Console.Write("{0}", string.Empty.PadRight(_CapsLockMessage.Length)); Console.SetCursorPosition(cursorLeft, cursorTop); } isAlreadyLocked = isCapsLockOn; } if (Console.KeyAvailable) { keyInfo = Console.ReadKey(intercept: true); if (keyInfo.Key == ConsoleKey.Enter) { isDone = true; continue; } if (!char.IsControl(keyInfo.KeyChar)) { consoleLine.Append(keyInfo.KeyChar); Console.Write(mask); } else if (keyInfo.Key == ConsoleKey.Backspace && consoleLine.Length > 0) { consoleLine.Remove(consoleLine.Length - 1, 1); if (Console.CursorLeft == 0) { Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); Console.Write(' '); Console.SetCursorPosition(Console.BufferWidth - 1, Console.CursorTop - 1); } else { Console.Write("\b \b"); } } if (isCapsLockOn) { cursorLeft = Console.CursorLeft; cursorTop = Console.CursorTop; originalForegroundColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.Write("{0}", _CapsLockMessage); Console.CursorLeft = cursorLeft; Console.CursorTop = cursorTop; Console.ForegroundColor = originalForegroundColor; } } } Console.WriteLine(); return consoleLine.ToString(); } 
  string pass = ""; Console.WriteLine("Enter your password: "); ConsoleKeyInfo key; do { key = Console.ReadKey(true); if (key.Key != ConsoleKey.Backspace) { pass += key.KeyChar; Console.Write("*"); } else { Console.Write("\b \b"); char[] pas = pass.ToCharArray(); string temp = ""; for (int i = 0; i < pass.Length - 1; i++) { temp += pas[i]; } pass = temp; } } // Stops Receving Keys Once Enter is Pressed while (key.Key != ConsoleKey.Enter); Console.WriteLine(); Console.WriteLine("The Password You entered is : " + pass); 

这会用红色方块掩盖密码,然后在input密码后恢复原来的颜色。

它不会阻止用户使用复制/粘贴来获取密码,但如果更多的是阻止某个人看着你的肩膀,这是一个很好的快速解决scheme。

 Console.Write("Password "); ConsoleColor origBG = Console.BackgroundColor; // Store original values ConsoleColor origFG = Console.ForegroundColor; Console.BackgroundColor = ConsoleColor.Red; // Set the block colour (could be anything) Console.ForegroundColor = ConsoleColor.Red; string Password = Console.ReadLine(); // read the password Console.BackgroundColor= origBG; // revert back to original Console.ForegroundColor= origFG; 

如果我正确地理解了这一点,你试图让退格键同时删除屏幕上的可见*字符和你的传递variables中的caching字符?

如果是这样,那么只要改变你的else块就可以了:

  else { Console.Write("\b"); pass = pass.Remove(pass.Length -1); }