Зачем же нужна авторизация? Что за вопрос, все же знают. Если коротко, то авторизация служит как для входа пользователя в систему, так и для ограничения прав на доступ к функциям системы. У меня он выделен, так сказать, в отдельный модуль, для переносимости, что позволяет использовать один и тот же код в разных проектах.
С чего же начинается авторизация? Ну, конечно же, с окна ввода пользователя и пароля! Вот как то так будет оно выглядеть:

Здесь все стандартно и понятно. Поле логина и пароля, и, конечно же, галочка «запомнить». Когда то в молодости я ее не использовал. Но ввод этой галочки явно облегчил жизнь моим пользователям. За кнопкой «Настройки» таится окошко настройки подключения к базе данных.
И что ж там внутри?
Функция main(), довольно все просто и понятно.
int main(int argc, char *argv[]) { QApplication a(argc, argv); // Устанавливаем кодеки QTextCodec::setCodecForLocale(QTextCodec::codecForName("cp1251")); QTextCodec::setCodecForTr(QTextCodec::codecForName("cp1251")); frmMain w; ProgSettings sett; DlgAuth dlg; dlg.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog); // Устанавливаем имя последнего сохраненного пользователя в поле логин // и галочку "Запомнить" dlg.setUserName(sett.LastUser()); dlg.setRemember(sett.IsRemember()); // Если стоит галочка "запомнить" // то подключаемся к БД(при условии валидности настроек), // и устанавливаем последний сохраненный пароль if (dlg.IsRemember() && DBConnector::CanConnectToDB()) { DBConnector::ConnectToDB(); dlg.setPassword(sett.SavePassword()); } // Или входим сразу с сохраненным паролем, либо показываем диалог авторизации if ((DBConnector::CanConnectToDB() && sett.IsRemember() && coreUsers::Auth(sett.LastUser(),sett.SavePassword())) || dlg.exec() == QDialog::Accepted) { w.show(); // Сохраняем последние п-ры входа sett.setLastUser(dlg.UserName()); sett.setSavePassword(dlg.Password()); sett.setIsReminder(dlg.IsRemember()); } else return 0; return a.exec(); }
Функция CanConnectToDB() проверяет корректность наших параметров для подключения к БД(если программа запущена в первые, то функция возвратит false, т.к. настроек еще нет);
Класс ProgSettings служит для работы с настройками программы, в нем нет ничего особенно, соот. и останавливаться не будем.
Отдельно стоит остановиться на функции Auth(), наверное самая главная функция.
bool coreUsers::Auth(QString login, QString pwd) { QSqlQuery sql; bool Ok = false; sql.exec(QString("SELECT * FROM %1 WHERE %2 = '%3'") .arg(UserTable::tableName()) .arg(UserTable::loginField()) .arg(login)); if (sql.lastError().isValid()) { QMessageBox::information(QApplication::activeWindow(),tr("Ошибка"), sql.lastError().text(),QMessageBox::Ok); return false; } if (sql.size() > 0) { sql.next(); if (QString::compare(Cryptor::Decode(sql.record().field(UserTable::pwdField()).value().toString()) ,pwd,Qt::CaseSensitive)!=0) { QMessageBox::information(QApplication::activeWindow(),tr("Ошибка"),tr("Неверный пароль! ") ,QMessageBox::Ok); } else { if (sql.record().field(UserTable::lockField()).value().toBool()) QMessageBox::information(QApplication::activeWindow(),tr("Ошибка"), tr("Пользователь '%1' заблокирован.").arg(login),QMessageBox::Ok); else { Ok = true; SetActiveUser(new SystemUser(sql.record().field(UserTable::idField()).value().toInt(), login,"", sql.record().field(UserTable::nameField()).value().toString())); } } } else QMessageBox::information(QApplication::activeWindow(),tr("Ошибка"), tr("Нет такого пользователя или неверный пароль!"),QMessageBox::Ok); return Ok; }
Без комментариев, за исключение функции SetActiveUser(), которая создает статический экземпляр от SystemUser класса, требуемый для дальнейшей работы по ограничению доступа к функциям всей программы.
Класс UserTable предстовляет собой класс обертку таблицы пользователей.
class UserTable { public: static QString tableName() { return "sy_user"; } static QString loginField() { return "us_login"; } static QString pwdField() { return "us_pwd"; } static QString idField() { return "us_id"; } static QString nameField() { return "us_name"; } static QString lockField() { return "us_lock"; } static QString onlineField() { return "us_online"; } static QString onlineTimeField(){ return "us_online_time"; } static bool IsEmpty(); // Создать первого пользователя системы для первого входа в систему static void CreateFirstUser(); };
Стоит отметить о сохранении паролей, они пишутся в реестр и таблицу базы данных зашифрованными. Пароль в таблице пользователей и пароль для подключения к серверу БД шифруются одинаковым алгоритмом и ключом. Кстати, не редко вижу на практике, что многие серьезные программы, пишут в системный реестр незашифрованные пароли, это как, нормально?
Шифрация паролей происходит на уровне приложения, следовательно, первый пользователь системы (без которого мы вообще не войдем в программу) создается при первой попытке входа в систему, вот такой функцией:
void UserTable::CreateFirstUser() { if (!QSqlDatabase::database().isOpen() && !UserTable::IsEmpty()) return; QSqlQuery sql; sql.exec(QString("INSERT INTO %1 (%2, %3) VALUES('admin', '%4');") .arg(tableName()) .arg(loginField()) .arg(pwdField()) .arg(Cryptor::Encode("admin"))); if (sql.lastError().isValid()) { qDebug() << sql.lastError().text(); } else { UserLimitTable::AddLimit(sql.lastInsertId().toInt(),100); } }
Тут же потребуется класс обертка для таблицы ограничений пользователей:
class UserLimitTable { public: static QString TableName() { return "sy_user_limit"; } static QString limitIdField() { return "ul_limit"; } static QString userIdField() { return "ul_us_id"; } static void AddLimit(int userID, int limitID); };
И на последок класс SystemUser:
class SystemUser { public: SystemUser(int id, QString login, QString pwd, QString name); // Возвращает список ограничений пользователя QList<int> Limits() {return limits;} int id() {return Id;} QString login() {return Login;} QString password() {return Password;} QString userName() {return UserName;} QDateTime startSessionTime() {return StartSessionTime;} void setId(int value) {Id = value;} void setLogin(QString value) { Login = value;} void setPassword(QString value) {Password = value;} void setUserName (QString value) {UserName = value;} void setStartSessionTime (QDateTime value) { StartSessionTime = value;} private: QList<int> limits; int Id; QString Login; QString Password; QString UserName; QDateTime StartSessionTime; };
Ограничения пользователя хранятся в обычном списке QList, который заполняется из таблицы лимитов пользователей в конструкторе SystemUser. Служит он для дальнейшего ограничения функций текущего пользователя.
В итоге мы получаем систему авторизации, подходящую практически для любой сложности приложений. На основе классов оберток таблиц, строятся все запросы к базе данных, что при переносе на другой проект, заменяются имена полей таблицы на свои. Что очень удобно.
Спасибо что дочитали до конца.

