Login system with multiple users

My program will check the username and password of one user, but once I create a new account, it will only accept login information of the very first user. I think I need it to read the next line in the file, but it only reads the top, thus only allowing the first user to login. I don't know how to make it accept more than one user login... I'll paste the snippit of the code that is in question...

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
 void createAccount() // Takes and stores users login information, username and password
{
   string username;
   string password;
   cout << "Please create a username" << endl;
   cin >> username;
   cout << "Please create a password" << endl;
   cin >> password;
   ofstream createaccount;
   createaccount.open("accounts.txt", ios::app); // Will store the users information.
   createaccount << username << " " << password << endl;
   createaccount.close();
   cout << "Account created!" << endl;

}
void bank :: login(void) // Takes information stored in create account. Most loaded function, also holds banking menu.
{
   string username;
   string password;
   char choice;
   bank decision;
   ifstream savedaccount;
   savedaccount.open("accounts.txt"); // accounts.txt will verify user information.
   cout << "Enter your username:" << endl;
   cin >> username;
   cout << "Enter your password:" << endl;
   cin >> password;
   string username2, password2;
   savedaccount >> username2 >> password2;
   savedaccount.close();
   if (username != username2 || password != password2)
    cout << "Incorrect login! Create new account or try again." << endl;
    while(username == username2 && password == password2) // Achieved by using accounts.txt match
    {
        choice = bankingMenu();


The file shows up like this - EXAMPLE

Bob 1234
Sarah 12345

But it will only accept Bob into the login system, not Sarah.
Last edited on
Any feedback please?
You're only extracting the first two words from your file, which are your first username and password. Since you're only reading the first two words your program doesn't know anything about the other entries.

You need to read all entries. One way of doing this is by creating a vector of accounts. Then, extract each line of the file. Assuming your file looks like this:

Bob 123
Sarah 456


Where Bob and Sarah are usernames, and where 123 and 456 are the corresponding passwords.
This means each line contains one username, followed by the corresponding password, separated by a single space.
After extracting a line, create two substrings, and assign those to a temporary account object. Finally, push a copy of the temporary account object onto your vector.

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
#include <iostream>
#include <string>
#include <fstream>
#include <vector>

struct Account {
	std::string username;
	std::string password;
};

int main(int argc, char* argv[]) {

	std::ifstream file("accounts.txt", std::ios::binary);
	if (!file) {
		std::cout << "There was an error reading the file!" << std::endl;
		return 1;
	}

	std::vector<Account> accounts;

	std::string line;
	while (std::getline(file, line)) {
		if (line.empty()) {
			continue;
		}

		auto it = line.find(" ");
		//Usernames and passwords are separated by one space.

		if (it != std::string::npos) {			
			std::string username = line.substr(0, it);
			std::string password = line.substr(it+1, line.npos);
			Account account = { username, password };
			accounts.push_back(account);
		}

	}

	for (auto account : accounts) {
		std::cout << account.username << std::endl;
		std::cout << account.password << std::endl;
	}

	return 0;
}
Last edited on
I'll show the rest of the program, because I tried implementing vector, but I have no clue how to do it with my current setup.

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <string>




using namespace std;

    char mainMenu();
    void createAccount(); // User creates own username/password to and is stored in accounts.txt
    char bankingMenu();
   class bank{ // Class is used in order to carry the variable bal through void functions
    int bal; // Balance, running total used in functions
    public :
    void deposit(void); // Will add money to the bal variable
    void withdraw(void); // Will subtract withdraw from bal
    void login(void); // Login achieved by using the accounts.txt file to check for username/password match
    void displayBalance();
    void ShowTransHist();}; // Gets transaction history from the file path string and display
int main()
{

    char choice;
    bank account;
    while (choice != 'q' || choice != 'Q')
    {
        choice = mainMenu();
        if (choice == 'q' || choice == 'Q'){
         cout << "Thanks for stopping by Justin's Bank!";   break;} // I use break a lot in this program. Great for terminating/going back a menu
        switch (choice)
        {
        case 'l':
        case 'L':
            account.login();
            break;
        case 'c':
        case 'C':
            createAccount();
            break;
        case 'v':
        case 'V':
            cout << "Thank you for using our bank and Future Computer Programmer ATM Machine! \nFor your continued support, we are offering 3% cash back on all debit purchases." << endl;
        default:
            cout << "Invalid choice!" << endl;
        }
    }
    return 0;
}
char mainMenu() // Function to display the main menu, not banking menu
{
    char choice;
    cout << "********** MAIN MENU ********** " << endl << endl;
    cout << "l(L) -> Login to Banking Menu" << endl;
    cout << "c -> Create New Account" << endl;
    cout << "v -> View Promotions" << endl;
    cout << "q -> Quit the Program" << endl;
    cout << "Enter your choice:" << endl;
    cin >> choice;
    return choice;

}
void createAccount() // Takes and stores users login information, username and password
{
   string username;
   string password;
   cout << "Please create a username" << endl;
   cin >> username;
   cout << "Please create a password" << endl;
   cin >> password;
   ofstream createaccount;
   createaccount.open("accounts.txt", ios::app); // Will store the users information.
   createaccount << username << " " << password << endl;
   createaccount.close();
   cout << "Account created!" << endl;

}
void bank :: login(void) // Takes information stored in create account. Most loaded function, also holds banking menu.
{
   string username;
   string password;
   char choice;
   bank decision;
   ifstream savedaccount;
   savedaccount.open("accounts.txt"); // accounts.txt will verify user information.
   cout << "Enter your username:" << endl;
   cin >> username;
   cout << "Enter your password:" << endl;
   cin >> password;
   string username2, password2;
   savedaccount >> username2 >> password2;
   savedaccount.close();
   if (username != username2 || password != password2)
    cout << "Incorrect login! Create new account or try again." << endl;
    while(username == username2 && password == password2) // Achieved by using accounts.txt match
    {
        choice = bankingMenu(); // Placed function here so that it will only appear if user logins.
        if (choice == 'q' || choice =='Q') break;
        switch (choice){


case 'd':
case 'D':
    decision.deposit();
    break;
case 'w':
case 'W':
    decision.withdraw();
    break;
case 'b':
case 'B':
    decision.displayBalance();
    break;
case 'r':
case 'R':
    decision.ShowTransHist();
    break;
default:
    cout << "Invalid choice!" << endl;

        }
}
}
char bankingMenu() // Banking menu, only opens if user achieves login.
{
    char choice;
    cout << "********* BANKING MENU *********" << endl << endl;
    cout << "d. Deposit Money" << endl;
    cout << "w. Withdraw Money" << endl;
    cout << "b. Check Balance" << endl;
    cout << "r. Review Account Activities History" << endl;
    cout << "q. Return to Main Menu" << endl;
    cout << "Enter your choice:" << endl;
    cin >> choice;
    return choice;
    }
void bank :: deposit(void) // Takes bal variable from bank class and keeps it as a constant total, deposit adds to bal
{
   long deposit;
   cout << "Enter how much you would like to deposit: ";
   cin >> deposit;
   bal = deposit+bal;
   cout << "You have deposited: $" << deposit << endl;
   if (deposit >= 100000)
    cout << "Now that is a lot of money!" << endl; // Easter egg

}
void bank :: withdraw(void) // Similar to deposit, but subtracts from bal.
{
    long withdraw;
    cout << "Enter how much you would like to withdraw: ";
    cin >> withdraw;
    if (bal > withdraw || bal == withdraw){
    bal= bal - withdraw;
    cout << "You have withdrawn: $" << withdraw << endl;}
    else if (bal < withdraw)
    cout << "You don't have enough funds to cover your withdraw request!" << endl;
}
void bank :: displayBalance() // Deposits and withdrawls are taken into account, and the constant total bal is displayed here.
{
    cout << "Your current balance is: $" << bal << endl;
    if (bal >= 1000000)
        cout << "Wow, you're a high roller!" << endl; // More easter eggs, I have fun with this!
}
void bank :: ShowTransHist()
{
   ofstream balance;
   int bal;
   balance.open("transHistory.output", std::ios_base::app);
   balance << bal << endl;
}
Is there a more simple way to read multiple users other than 1 besides using a vector? I'm a beginner to C++ and I don't really have a solid grasp on vector/arrays yet.
Can anyone else chime in?
The thing is, you don't know how many accounts your file has beforehand. It could have one, or two, or hundreds. You can't hardcode that sort of thing, so you'll need to rely on some dynamic container to accumulate the accounts as you read them. This is why I chose a vector.

It's a different story if you know that your file will always have, let's say three, and only three accounts at all times. If you have a guarantee like that you can do basically what you did in your first snippet on line 29, only three more times.
I think we are required to have 2 accounts, so I would create another ifstream key?
Such as... savedaccount >> username2 >> password2;

And then for my other account

savedaccount2 >> username2 >> password2?

The TA said she'll be logging in from 2 different accounts so I'm guessing we'll only need to have 2 in our program.

Could I declare it like this... ifstream savedaccount, savedaccount2;?

Well I have to go to bed, I'll try some stuff tomorrow and get back.
Last edited on
Bumpity bump. Xismn, if you're here, can you confirm what I said in my last post?
Bump...
Sorry for the late response.

If the file looks like this:
bob 123
tom 456


You can do the following:
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
#include <iostream>
#include <string>
#include <fstream>

int main() {

	std::string filename = "accounts.txt";
	std::ifstream file(filename, std::ios::binary);

	if (!file) {
		std::cout << "There was an error reading the file!" << std::endl;
		return 1;
	}

	std::string username_one;
	std::string username_two;

	std::string password_one;
	std::string password_two;

	file >> username_one >> password_one;
	file >> username_two >> password_two;

	std::cout << "Username #1:\t" << username_one << std::endl;
	std::cout << "Password #1:\t" << password_one << std::endl;
	std::cout << "Username #2:\t" << username_two << std::endl;
	std::cout << "Password #2:\t" << password_two << std::endl;

	return 0;
}
Last edited on
Topic archived. No new replies allowed.