📜 ⬆️ ⬇️

Application Authorization

Good day to all. In this article, I will describe my practical experience in designing an authorization system, in particular in C ++ Qt 4. For many experienced programmers, everything below seems banal, but I think this experience will be useful for programmers who are starting out on their path. Words at least, mostly clipping code.

Why do we need authorization? What kind of question they still know. In short, the authorization serves both to enter the user into the system, and to limit the rights to access the system functions. I have it allocated, so to speak, in a separate module for portability, which allows you to use the same code in different projects.

Where does authorization begin? Well, of course, from the user input window and password! Here's how it will look like this:


')
Here everything is standard and clear. Login field and password, and, of course, a tick "remember". Once in my youth I did not use it. But the introduction of this tick clearly made life easier for my users. Behind the "Settings" button there is a window for setting up a connection to the database.

And what is there inside?

The main () function is pretty simple.

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(); } 


The function CanConnectToDB () checks the correctness of our parameters for connecting to the database (if the program is started at first, the function will return false, because there are no settings yet);

The class ProgSettings is used to work with the program settings, there is nothing in it especially, respectively. and we will not stop.
Separately, it is worthwhile to dwell on the Auth () function, probably the most important function.

 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; } 


No comment, except for the SetActiveUser () function, which creates a static instance from the SystemUser class required for further work on restricting access to the functions of the entire program.
The UserTable class is a wrapper class table of users.

 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(); }; 


It is worth noting about saving passwords, they are written to the registry and the database table is encrypted. The password in the user table and the password for connecting to the database server are encrypted with the same algorithm and key. By the way, it is not rare to see in practice that many serious programs write unencrypted passwords to the registry, this is how, normal?
Password encryption occurs at the application level, therefore, the first user of the system (without which we will not enter the program at all) is created when you first try to log in to the system, this is the function:

 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); } } 


You will also need a wrapper class for the user restriction table:

 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); }; 


And lastly, the SystemUser class:

 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; }; 


User restrictions are stored in a regular QList list, which is populated from the user limit table in the SystemUser constructor. It serves to further limit the functions of the current user.

As a result, we get an authorization system that is suitable for almost any application complexity. Based on the table wrapper classes, all database queries are built, which, when transferred to another project, replace the table field names with their own. Which is very convenient.

Thank you for reading to the end.

Source: https://habr.com/ru/post/150755/


All Articles