LINUX.ORG.RU

Диалог авторизации

 , ,


0

1

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

#ifndef AUTHDIALOG_HPP
#define AUTHDIALOG_HPP

#include <QtGui>

class AuthDialog : public QDialog {
    Q_OBJECT

public:
    AuthDialog(QWidget *parent = 0);
    ~AuthDialog();

private slots:
    void onAcceptButtonPressed();
    void onAcceptErrorButtonPressed();
    void moveFocusToPasswordLine();
    void moveFocusToAcceptButton();

private:
    QLineEdit* usernameLine;
    QLineEdit* passwordLine;
    QPushButton* acceptButton;
    QPushButton* cancelButton;
    QPushButton* errorAcceptButton;
    QDialog* errorWindow;
    bool checkAuth();
};

#endif // AUTHDIALOG_HPP
#include "authdialog.hpp"

AuthDialog::AuthDialog(QWidget *parent)
    : QDialog(parent) {
    //Login window
    setWindowTitle(tr("Login"));
    usernameLine = new QLineEdit(this);
    passwordLine = new QLineEdit(this);
    connect(usernameLine, SIGNAL(editingFinished()),
            this, SLOT(moveFocusToPasswordLine()));
    passwordLine->setEchoMode(QLineEdit::Password);
    connect(passwordLine, SIGNAL(editingFinished()),
            this, SLOT(moveFocusToAcceptButton()));
    QLabel* usernameLabel = new QLabel(tr("Username"), this);
    QLabel* passwordLabel = new QLabel(tr("Password"), this);
    acceptButton = new QPushButton(tr("Accept"), this);
    acceptButton->setAutoDefault(FALSE);
    connect(acceptButton, SIGNAL(clicked()),
            this, SLOT(onAcceptButtonPressed()));
    cancelButton = new QPushButton(tr("Cancel"), this);
    cancelButton->setAutoDefault(FALSE);
    connect(cancelButton, SIGNAL(clicked()),
            this, SLOT(reject()));
    QHBoxLayout* buttonsLayout = new QHBoxLayout;
    buttonsLayout->setAlignment(Qt::AlignCenter);
    buttonsLayout->addWidget(acceptButton);
    buttonsLayout->addWidget(cancelButton);
    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(usernameLabel);
    mainLayout->addWidget(usernameLine);
    mainLayout->addWidget(passwordLabel);
    mainLayout->addWidget(passwordLine);
    mainLayout->addLayout(buttonsLayout);
    setLayout(mainLayout);
    //Error window
    errorWindow = new QDialog;
    errorWindow->setWindowTitle(tr("Error"));
    errorAcceptButton = new QPushButton(tr("Ok"), errorWindow);
    connect(errorAcceptButton, SIGNAL(clicked()),
            this, SLOT(onAcceptErrorButtonPressed()));
    QLabel* errorLabel = new QLabel(tr("Incorrect username or password!"), errorWindow);
    QVBoxLayout* errorLayout = new QVBoxLayout(errorWindow);
    errorLayout->setAlignment(Qt::AlignCenter);
    errorLayout->addWidget(errorLabel);
    errorLayout->addWidget(errorAcceptButton);
    errorWindow->setLayout(errorLayout);
}


AuthDialog::~AuthDialog() {

}


void AuthDialog::onAcceptButtonPressed() {
    if (checkAuth()) {
        emit accepted();
        delete errorWindow;
        hide();
    }
    else {
        // deactivate the dialog, reset its fields and show "error message" window
        this->setDisabled(TRUE);
        errorWindow->show();
        usernameLine->clear();
        passwordLine->clear();
    }
}


bool AuthDialog::checkAuth() {
    if ((usernameLine->text() == "username") && (passwordLine->text() == "password")) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}


void AuthDialog::onAcceptErrorButtonPressed() {
    // hide the "error message" window and activate the dialog
    errorWindow->hide();
    this->setDisabled(FALSE);
    usernameLine->setFocus();
    acceptButton->setDefault(FALSE);
}


void AuthDialog::moveFocusToPasswordLine() {
    // move the focus to the "password" input field when pressed "Enter" key
    passwordLine->setFocus();
}


void AuthDialog::moveFocusToAcceptButton() {
    // move the focus to the "accept" button and make it active
    acceptButton->setFocus();
    acceptButton->setDefault(TRUE);
}
#include "authdialog.hpp"
#include <QtCore>
#include <QtGui>

int main(int argc, char** argv) {
    QApplication app(argc, argv);
    QMainWindow mainWindow;
    mainWindow.setWindowTitle("MainWindow");
    mainWindow.setMinimumSize(QSize(600, 300));
    AuthDialog authDialog;
    authDialog.show();
    QObject::connect(&authDialog, SIGNAL(accepted()),
                     &mainWindow, SLOT(show()));
    QObject::connect(&authDialog, SIGNAL(rejected()),
                     &app, SLOT(closeAllWindows()));
    return app.exec();
}

  • утечка памяти (errorWindow) при закрытии или отмене авторизации.
  • невозможно мышкой вернуться в username после перехода на password
anonymous
()
Ответ на: комментарий от anonymous

Спасибо. Про утечку понял. Перенес удаление в деструктор. А вот про второй пункт буду думать. Может есть мысли?

baldman88
() автор топика
Ответ на: комментарий от anonymous

Авторизовать пользователя =) А вообще — это просто заготовка. Конкретная цель — государственная тайна.

baldman88
() автор топика
Ответ на: комментарий от Dantix

Не обязательно QML, можно воспользоваться Qt Designer'ом и оставить в «*.cpp» только логику, вынеся весь интерфейс в «*.ui»-файл. Странно, что ТС так не сделал, хотя это дело принципа и личного удобства.

EXL ★★★★★
()
Ответ на: комментарий от EXL

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

baldman88
() автор топика
Ответ на: комментарий от baldman88

Авторизовать пользователя =)

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

В openssl есть функция md5(3), используй её, и храни md5 пароля. Например для «passwd» хеш 6af286f0509e7c166abf710850f44fc4 (естественно, именно этот пароль подбирается за 10 минут тупым перебором)

Если юзеров более одного, и пароли не забиты в код, то юзай md5+соль битов в 100.

emulek
()
Ответ на: комментарий от anonymous

И со вторым разобрался. Еще раз спасибо.

baldman88
() автор топика
Ответ на: комментарий от emulek

Неужели остались настолько наивные люди? Написал же по русски — это просто заготовка! Логика самой функции checkAuth() будет изменена. Ну и логины с паролями будут другими =)

baldman88
() автор топика

ну как бы форма работать не будет. сигнала accepted() в списке публичных сигналов нет. не достаточно просто написать emit accepted(), нужно еще и в заголовке объявить. не мешало б вообще иметь 2 сигнала: accepted и regected.

madsquir
()
Ответ на: комментарий от madsquir

Ну вот, опять. Посты за звезды? Как насчет того, что эти сигналы уже определены в наследуемом классе? И откуда уверенность, что работать не будет? Вы попробуйте собрать и запустить.

baldman88
() автор топика
Ответ на: комментарий от baldman88

не надо кипишевать=) я думал наследование от qwidget.

ну и с фокусом как тут заметили проблема.

madsquir
()
Ответ на: комментарий от baldman88

Написал же по русски — это просто заготовка! Логика самой функции checkAuth() будет изменена.

коммент-бы приписал.

Ну и логины с паролями будут другими =)

а это я догадался.

emulek
()
Ответ на: комментарий от madsquir

Настроение днем было не очень. А вот это дельный совет. Спасибо.

baldman88
() автор топика

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

как одноразовый код пойдёт, тех.мелочи уже указали. НО если не хочешь выбрасывать код в корзинку, а использовать многократно - неверная иерархия классов, нехватает обобщений и разделения логики на слои.

По хорошему AuthDialog должен расширять QDialog добавляя только специфику диалогов авторизации: ограничения кол-ва попыток ввода, ограничения по времени, асинхронная и возможно длительная процедура авторизации, борьба с заведомо невалидными данными,кейлогерами, иньекциями и прочее;

Такой класс вам понадобиться потом неоднократно - от него будете производить без копипасты всякие LoginPassDialog, SQLConnectDialog, DomainJoin и прочая.

ps. Понимаю, что конечно-же лень ради простого диалога порождать целых ДВА класса.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Спасибо за столь обширный ответ. Но в данном случае вы отчасти правы — лень. Да и знаний пока не столько много. Нужно просто окно для ввода логина и пароля, и, если они верны, показа основного окна. Очень интересует, правильно ли соединять сигнал accepted() со слотом show()? Может есть другие варианты?

baldman88
() автор топика
Ответ на: комментарий от baldman88

Нужно просто окно для ввода логина и пароля, и, если они верны, показа основного окна.

не вижу причин не делать это хорошо.

помимо выше сказанного можно ещё и по use-case пробежаться:

- диалог работает самым первым и по хорошему должен как-то «представиться» - юзер должен знать для чего он вводит логин/пароль.

- кнопка Ok разрешена прям сразу, хотя логично разрешать её только при непустых (либо корректных) логин/пароль. Сейчас есть случаи когда метод checkAuth вызывается при заранее известном негативном результате.

- при ошибке авторизации выдаётся окно с одной кнопкой, когда альтернатив у юзера две - повторить попытку либо покинуть программу. Надо или добавлять кнопку или сообщать об ошибке не покидая основного окна.

и так далее

MKuznetsov ★★★★★
()
Ответ на: комментарий от baldman88

и раз пошла такая пьянка с критикой :

errorWindow и его ошмёткам вообще нечего делать в этом классе. Это либо внешний синглетон или метод приложения или как-там ещё придумаете (хоть QErrorMessage на первое время), но это отдельный механизм - сообщать юзеру о ошибках и проблемах придётся часто и из разных мест приложения.

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.