发布
2009年11月7日(最后更新:2012年1月29日)

屏蔽密码输入

评分:3.8/5(149票)
*****

目录



Unix/Linux

示例 1


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;

int getch() {
    int ch;
    struct termios t_old, t_new;

    tcgetattr(STDIN_FILENO, &t_old);
    t_new = t_old;
    t_new.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &t_new);

    ch = getchar();

    tcsetattr(STDIN_FILENO, TCSANOW, &t_old);
    return ch;
}





string getpass(const char *prompt, bool show_asterisk=true)
{
  const char BACKSPACE=127;
  const char RETURN=10;

  string password;
  unsigned char ch=0;

  cout <<prompt<<endl;

  while((ch=getch())!=RETURN)
    {
       if(ch==BACKSPACE)
         {
            if(password.length()!=0)
              {
                 if(show_asterisk)
                 cout <<"\b \b";
                 password.resize(password.length()-1);
              }
         }
       else
         {
             password+=ch;
             if(show_asterisk)
                 cout <<'*';
         }
    }
  cout <<endl;
  return password;
}


int main()
{
  const char *correct_password="null";

  string password=getpass("Please enter the password: ",true); // Show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;


  password=getpass("Please enter the password: ",false); // Do not show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;

  return 0;
}


示例 2 - 使用 getpass() 函数

根据 Linux 程序员手册,此函数已过时,应尽可能避免使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <cstdlib>
#include <iostream>
using namespace std;

const char *mypass="null";

int main()
{
char *password=getpass("Enter password: ");

if(strcmp(password,mypass)==0) cout <<"Correct password!\n";
else cout <<"Incorrect password!\n";


return 0;
}






Windows

示例 1 - 使用 WinAPI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;


string getpass(const char *prompt, bool show_asterisk=true)
{
  const char BACKSPACE=8;
  const char RETURN=13;

  string password;
  unsigned char ch=0;

  cout <<prompt<<endl;

  DWORD con_mode;
  DWORD dwRead;

  HANDLE hIn=GetStdHandle(STD_INPUT_HANDLE);

  GetConsoleMode( hIn, &con_mode );
  SetConsoleMode( hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT) );

  while(ReadConsoleA( hIn, &ch, 1, &dwRead, NULL) && ch !=RETURN)
    {
       if(ch==BACKSPACE)
         {
            if(password.length()!=0)
              {
                 if(show_asterisk)
                     cout <<"\b \b";
                 password.resize(password.length()-1);
              }
         }
       else
         {
             password+=ch;
             if(show_asterisk)
                 cout <<'*';
         }
    }
  cout <<endl;
  return password;
}



int main()
{
  const char *correct_password="null";

  cout <<"Test 1: echoing enabled"<<endl;
  string password=getpass("Please enter the password: ",true); // Show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;

  cout <<"\nTest 2: echoing disabled"<<endl;
  password=getpass("Please enter the password: ",false); // Do not show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;

  return 0;
}





示例 2 - 使用 conio.h

此代码与前一个示例类似,但使用了 conio.h 头文件中的 getch() 函数来获取无缓冲的控制台输入。请注意,conio.h 是 Borland 特有的头文件,应尽可能避免使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;


string getpass(const char *prompt, bool show_asterisk=true)
{
  const char BACKSPACE=8;
  const char RETURN=13;

  string password;
  unsigned char ch=0;

  cout <<prompt<<endl;

  while((ch=getch())!=RETURN)
    {
       if(ch==BACKSPACE)
         {
            if(password.length()!=0)
              {
                 if(show_asterisk)
                 cout <<"\b \b";
                 password.resize(password.length()-1);
              }
         }
       else if(ch==0 || ch==224) // handle escape sequences
         {
             getch(); // ignore non printable chars
             continue;
         }
       else
         {
             password+=ch;
             if(show_asterisk)
                 cout <<'*';
         }
    }
  cout <<endl;
  return password;
}


int main()
{
  const char *correct_password="null";

  string password=getpass("Please enter the password: ",true); // Show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;


  password=getpass("Please enter the password: ",false); // Do not show asterisks
  if(password==correct_password)
      cout <<"Correct password"<<endl;
  else
      cout <<"Incorrect password. Try again"<<endl;

  return 0;
}

请注意,如果密码长度超过控制台宽度(80 个字符),退格键将无法删除上一行中的星号。





使用 curses 库

Curses 库是跨平台控制台操作的最佳选择之一。请记住,该库是为 C 编程语言设计的,因此您无法将其与 C++ iostream 一起使用。


示例 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <string>
#include <curses.h>
using namespace std;


string getpass(const char *prompt)
{
  printw(prompt);
  noecho();  // disable character echoing

  char buff[64];
  getnstr(buff,sizeof(buff));

  echo(); // enable character echoing again
  return buff;
}

int main()
{
   const string correct_password="null";

   initscr(); // enable ncurses

   string pwd=getpass("Please enter the password: ");

   if(correct_password==pwd)
       printw("\nCorrect password!");
   else
       printw("\nIncorrect password. Try again");


    getch(); // Wait for a keypress
    endwin(); // disable ncurses

    return 0;
}


示例 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <string>
#include <curses.h>
using namespace std;


string getpass(const char *prompt, bool show_asterisk=true)
{
  const char BACKSPACE=8;
  const char RETURN=10; // Note: 10 for curses, 13 for conio

  string password;
  unsigned char ch=0;

  printw(prompt);
  printw("\n");

  noecho(); // Disable echoing

  while((ch=getch())!=RETURN)
    {
       if(ch==BACKSPACE)
         {
            if(password.length()!=0)
              {
                 if(show_asterisk)
                 printw("\b \b");
                 password.resize(password.length()-1);
              }
         }
       else if(ch!=27) // ignore 'escape' key
         {
             password+=ch;
             if(show_asterisk)
                 printw("*");
         }
    }

  echo();
  printw("\n");
  return password;
}





int main()
{
  initscr();

  const char *correct_password="null";

  printw("Test 1: echoing enabled\n");
  string password=getpass("Please enter the password: ",true); // Show asterisks
  if(password==correct_password)
      printw("Correct password!\n");
  else
      printw("Incorrect password. Try again\n");

  printw("\nTest 2: echoing disabled\n");
  password=getpass("Please enter the password: ",false); // Do not show asterisks
  if(password==correct_password)
      printw("Correct password");
  else
      printw("Incorrect password. Try again");

  printw("\n\nPress any key to continue...");
  getch();
  endwin();
  return 0;
}


备注
1. 在此处下载 curses:
http://sourceforge.net/projects/pdcurses/files/
2. 您必须将您的项目与 pdcurses.lib 库链接。