問題
程序不會停止找到一個匹配後搜索匹配。由於比賽結束後測試的數值將不匹配,因此會出現混亂。
讓我們來看,當我們爲分別MMM和用戶名和密碼,輸入執行下面的代碼出現這種情況:
for(int i=0;i<=3;i++){
if(usernameinput ==username[i] && passinput==password[i])
{
flag=true;
}
else if (usernameinput !=username[i] && passinput!=password[i])
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
}
迭代1:
if("mmm" == "mmm" && "1234" == "1234") // both true. Enter
{
flag=true; // flag is now true
}
else if ("mmm" != "mmm" && "1234" != "1234")
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
現在,因爲沒有任何事情告訴程序匹配已經找到,我們可以停止查找,我們繼續進行迭代2:
if("mmm" == "nnnn" && "1234" == "1212") // false
{
flag=true;
}
else if ("mmm" != "mmm" && "1234" != "1234") // both false, enter
{
flag=false; // flag is now false Ooops.
cout<<"please enter correct username and password"<<endl;
}
輸出,即使憑據是正確的,flag
將是錯誤的,用戶將被警告三次漏報。呸。
please enter correct username and password
please enter correct username and password
please enter correct username and password
我們需要退出循環時,我們得到了一個匹配。顯而易見的解決方案是這樣的:
if(usernameinput ==username[i] && passinput==password[i])
{
flag=true;
break;
}
別急!還有更多!如果輸入是mmm和?
迭代1:
if("mmm" == "mmm" && "1235" == "1234") //Second case fails
{
flag=true;
break;
}
else if ("mmm" != "mmm" && "1234" != "1234") // first case fails
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
我們不進入要麼情況。 flag
仍然是錯誤的,入侵者沒有進入,但這看起來很醜,仍然給你三條錯誤信息。我們可以做得更好。
解決方案
做一個函數:
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
bool rval = false;
for(int i=0;i<=3;i++)
{
if(uname== username[i])
{
if (pword==password[i])
{
rval = true; // could just return true here, but some folk get uptight
// over multiple returns in a function
}
break;
}
}
return rval;
}
調用函數不會像
if (checkcredentials(usernameinput, passinput))
{
// let the user in.
}
else
{
cout<<"please enter correct username and password"<<endl;
}
注意,檢查密碼函數什麼都不做,但檢查的憑據。所有與用戶的通信都在其他地方完成。這使得該功能很簡單。它只做一件事,它是由函數名稱描述的一件事。
安全提示:在向用戶返回消息之前等待一些小的隨機數量的時間。這與試圖通過對響應進行計時來猜測憑證的大小或憑證數據庫的大小的任何人的首腦混淆。
這可以通過將用戶名和密碼配對並只有一個數組進行進一步清理。這可確保用戶名與密碼匹配,並且沒有人添加用戶名而不添加密碼。
pair<string, string> credentials[]={ // array of pairs
{"mmm", "1234"},
{"nnnn", "1212"},
{"rrrr", "1234"},
{"aaa", "1212"}
};
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
bool rval = false;
for(auto & cred: credentials)
{
if(uname == cred.first)
{
if (pword == cred.second)
{
rval = true;
}
break;
}
}
return rval;
}
Documentation on pair.
這可以用一個更聰明的數據結構得到改善。 map
是一個關聯容器,在這種情況下,根據密鑰,用戶名查找一個值,密碼。
map<string, string> credentials={
{"mmm", "1234"},
{"nnnn", "1212"},
{"rrrr", "1234"},
{"aaa", "1212"}
};
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
auto cred = credentials.find(uname); // look for user name
if (cred != credentials.end() && // username exists
cred->second == pword) // password matches
{
return true;
}
return false;
}
Documentation on map.
題外話:而不是密碼和用戶名分離成自己陣列使用配對結構將它們分組,並只有一個陣列。需要較少的簿記。 – user4581301