Ofstream, или как создать локальное подключение

Здравствуйте, у меня возникал такой вопрос. Мне нравится пользоваться библиотекой «fstream», но я не мог сделать одну вещь. Куда бы вы не заходили: сайты, игры и тд, вам нужно было, либо зарегистрироваться, либо войти. Так вот, зарег. зашли, на сервер, то, куда-то появится ваши данные: логин, пароль, Ip. Если мы зайдем туда, где надо вводить данные, но если мы введем не правильно, то нам показывают ошибку. Так вот, переходим в c++

Как сделать с помощью fstream как бы сервер для входа. Те данные будут находится в блокноте, и по этим данным можно было зайти.
Например:

server.txt
Admin||12345

И в консоли:
Введите логин:
Admin
Введите пароль:
12345
Вы успешно зашли

Или

Введите логин:
Adm
Введите пароль:
112345
Данные неверные

Эскизно программа может выглядеть так:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

using namespace std;

class Account {
public:
    static bool check(const string& str);

    Account() {}
    Account (const string& a_username, const string& a_password) : username(a_username), password(a_password) {}

    bool validate(const string& a_username, const string& a_password);

    friend ostream& operator << (ostream& os, const Account& acc);
    friend istream& operator >> (istream& is, Account& acc);

private:
    string username, password;
};

bool Account::check(const string& str) {
    // проверка строки на допустимость использования в
    // качестве имени пользователя и пароля
    if (str.size() == 0)
        return false;
    size_t ssize = str.size();
    for (size_t i = 0; i < ssize; i++) {
        if (str[i] == ' ')
            return false;
    }
    return true;
}

bool Account::validate(const string& a_username, const string& a_password) {
    return a_username == username && a_password == password;
}

ostream& operator << (ostream& os, const Account& acc) {
    os << acc.username << ' ' << acc.password << endl;
    return os;
}

istream& operator >> (istream& is, Account& acc) {
    is >> acc.username >> acc.password;
    return is;
}


const char *datafilename = "server.txt";

void reg() {

    cout << "\n--- Регистрация нового пользователя ---\n\n";
    bool ok;
    string name, pass;
    do {
        cout << "Имя пользователя: ";
        cin >> name;
        cout << "Пароль: ";
        cin >> pass;
        ok = Account::check(name) && Account::check(pass);
        if (!ok)
            cout << "*** Неверно указано имя пользователя или пароль. Попробуйте снова...\n\n";
    } while (!ok);

    Account acc(name, pass);

    ofstream fout(datafilename, ios::out | ios::app);
    if (fout) {
        fout << acc;
    }
    else {
        cout << "*** Невозможно открыть файл \"" << datafilename << "\" на запись" << endl;
    }
}

void enter() {

    string name, pass;
    cout << "Имя пользователя: ";
    cin >> name;
    cout << "Пароль: ";
    cin >> pass;

    Account acc;
    bool ok = false;
    ifstream fin(datafilename);
    if (fin) {
        while (fin) {
            fin >> acc;
            ok = acc.validate(name, pass);
            if (ok)
                break;
        }
    }
    else {
        cout << "*** Невозможно открыть файл \"" << datafilename << "\" на чтение" << endl;
        return;
    }

    if (ok) {
        cout << "*** Доступ разрешён" << endl;
    }
    else {
        cout << "*** Доступ запрещён" << endl;
    }
}

int main(void) {

    setlocale(LC_ALL, ".1251");

    bool ok;
    int choice;
    do {
        ok = true;
        cout << "1. Войти\n2. Зарегистрироваться\n0. Выйти из программы\n\n> ";
        cin >> choice;
        switch (choice) {
        case 1:
            enter();
            break;
        case 2:
            reg();
            break;
        case 0:
            break;
        default:
            cout << "*** Неверный выбор. Попробуйте снова...\n\n";
            ok = false;
        }
    } while (!ok);

    system("pause");
    return 0;
}

Когда будешь тестировать программу, сначала «зарегистрируйся», а потом пытайся «войти». После «регистрации» посмотри в каталоге запуск файл server.txt.

Можно также зарегистрировать несколько пользователей (проверку на повтор регистрационных данных не делал).

В качестве бонуса, постарался продемонстрировать работу с классами и перегрузку операторов ввода/вывода в поток для класса.

Пароль не нужно хранить в открытом виде. Обычно используют необратимое хеширование при сохранении пароля на диск.

При проверке пароля, такому же хешированию подвергается введенный пользователем пароль. В случае совпадение с оригинальными хешем, вход считается успешным.

По той причине, что пользователей может быть много, лучше сначала найти нужную запись по логину, а потом уже проверять пароль.

Для шифрования пароля можно использовать bcrypt.

Вообще, для system нужен <cstdlib>. В Visual Studio он (system) по умолчанию в работает без подключения <cstdlib>. Тем не менее, его стоит подключать явно.

Если честно, то мне ясна суть физически, а вот уже если самому написать, то будут затруднения.

Nikitaz58, а что конкретно непонятно? Вроде никакой экзотики не использовал...

Например вот это

   bool validate(const string& a_username, const string& a_password);

    friend ostream& operator << (ostream& os, const Account& acc);
    friend istream& operator >> (istream& is, Account& acc);

private:
    string username, password;
};

bool Account::check(const string& str) {
    // проверка строки на допустимость использования в
    // качестве имени пользователя и пароля
    if (str.size() == 0)
        return false;
    size_t ssize = str.size();
    for (size_t i = 0; i < ssize; i++) {
        if (str[i] == ' ')
            return false;
    }
    return true

Класс Account предназначен для хранения и работы со «сладкой парочкой» логин-пароль. В приватных переменных класса хранятся строки логина (username) и пароля (password).

Статический метод класса check() проверяет строку-кандидат на логин или пароль на допустимость. Сейчас проверяется, что строка не пустая и что в строке отсутствуют пробелы. Сюда можно дописать любые другие проверки, например, что строка не содержит кириллицу.

Метод validate() — это просто проверка совпадения строк, переданных в качестве параметров, со строками логина-пароля, которые хранятся в экземпляре класса.

Две «дружественные» функции

    friend ostream& operator << (ostream& os, const Account& acc);
    friend istream& operator >> (istream& is, Account& acc);

осуществляют вывод логина-пароля в поток и ввод из потока соответственно. Причём, поскольку для потоков в этих функциях используются менее специализированные классы istream и ostream, то эти функции могут использоваться и для консольного, и для файлового ввода-вывода, и для ввода-вывода в памяти (strstream).

Кстати, если принять во внимание замечание selevit'а по поводу шифрования и хранения регистрационной информации, то можно увидеть, что это всё можно реализовать не затрагивая интерфейса класса Account: надо изменить только реализацию методов класса. Следовательно вызывающий код останется без изменений. Это — одно из основных преимуществ ООП.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.