第71课 - 登录对话框的改进

版权声明:课程笔记内容整理于狄泰软件 https://blog.csdn.net/qq_39654127/article/details/81941535

1、第一个版本对话框

 第18课 - 登录对话框实例分析

2、问题: 

没有实现验证码功能,容易被恶意程序攻

击,盗取用户名和密码。 

 

3、登录对话框的改进 

需要主意的问题 

       -验证码必须动态随机产生 

       -验证码的显示避开使用标准组件(标签,文本框,等)

       -验证码应该附带足够多的障碍增加程序识别难度 

 解决方案 

         1. 随机产生目标验证码 

         2. 将验证码直接绘制于登录对话框 

         3. 验证码中的字符颜色随机改变 

         4. 在验证码区域随机绘制噪点 

关于随机数 

       -计算机无法产生真正意义上的随机数 

       -计算机只能模拟随机数序列(伪随机数) 

       -随机种子决定每次产生的随机序列是否相同 

 

随机产生验证码 

                                                          随机产生四个大小写字母

验证码绘制 

                                      验证码中的每个字符必须分开绘制(Best)

 

 

4、编程实验 

绘制验证码区域,随机验证码     71-1.pro 

QLoginDialog.h

#ifndef _QLOGINDIALOG_H_
#define _QLOGINDIALOG_H_

#include <QtGui/QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTimer>

class QLoginDialog : public QDialog
{
    Q_OBJECT
private:
    QLabel UserLabel;
    QLabel PwdLabel;
    QLabel CaptLabel;
    QLineEdit UserEdit;
    QLineEdit PwdEdit;
    QLineEdit CaptEdit;
    QPushButton LoginBtn;
    QPushButton CancelBtn;
    QString m_user;
    QString m_pwd;
    QString m_captcha;
    Qt::GlobalColor* m_colors;
    QTimer m_timer;
private slots:
    void LoginBtn_Clicked();
    void CancelBtn_Clicked();
    void Timer_Timeout();
protected:
    void paintEvent(QPaintEvent *);
    QString getCaptcha();
    Qt::GlobalColor* getColors();
public:
    QLoginDialog(QWidget *parent = 0);
    QString getUser();
    QString getPwd();
    ~QLoginDialog();
};


#endif

QLoginDialog.cpp

#include "QLoginDialog.h"
#include <QPainter>
#include <QTime>
#include <QDebug>
#include <QMessageBox>

QLoginDialog::QLoginDialog(QWidget* parent) : QDialog(parent, Qt::WindowCloseButtonHint),
    UserLabel(this), PwdLabel(this), CaptLabel(this),
    UserEdit(this), PwdEdit(this), CaptEdit(this),
    LoginBtn(this), CancelBtn(this)
{
    UserLabel.setText("User ID:");
    UserLabel.move(20, 30);
    UserLabel.resize(60, 25);

    UserEdit.move(85, 30);
    UserEdit.resize(180, 25);

    PwdLabel.setText("Password:");
    PwdLabel.move(20, 65);
    PwdLabel.resize(60,25);

    PwdEdit.move(85, 65);
    PwdEdit.resize(180, 25);
    PwdEdit.setEchoMode(QLineEdit::Password);

    CaptLabel.setText("Captcha:");
    CaptLabel.move(20, 100);
    CaptLabel.resize(60, 25);

    CaptEdit.move(85, 100);
    CaptEdit.resize(85, 25);

    CancelBtn.setText("Cancel");
    CancelBtn.move(85, 145);
    CancelBtn.resize(85, 30);

    LoginBtn.setText("Login");
    LoginBtn.move(180, 145);
    LoginBtn.resize(85, 30);

    m_timer.setParent(this);

    setWindowTitle("Login");
    setFixedSize(285, 205);

    connect(&m_timer, SIGNAL(timeout()), this, SLOT(Timer_Timeout()));
    connect(&LoginBtn, SIGNAL(clicked()), this, SLOT(LoginBtn_Clicked()));
    connect(&CancelBtn, SIGNAL(clicked()), this, SLOT(CancelBtn_Clicked()));

    qsrand(QTime::currentTime().second() * 1000 + QTime::currentTime().msec());//种下种子

    m_captcha = getCaptcha();
    m_colors = getColors();

    m_timer.start(100); 
}

void QLoginDialog::LoginBtn_Clicked()
{
    qDebug() << "LoginBtn_Clicked() Begin";

    QString captcha = CaptEdit.text().replace(" ", "");

    if( m_captcha.toLower() == captcha.toLower() )//不区分大小写
    {
        m_user = UserEdit.text().trimmed();
        m_pwd = PwdEdit.text();

        if( m_user == "" )
        {
            QMessageBox::information(this, "Info", "User ID can NOT be empty!");
        }
        else if( m_pwd == "" )
        {
            QMessageBox::information(this, "Info", "Password can NOT be empty!");
        }
        else
        {
            done(Accepted);
        }
    }
    else
    {
        QMessageBox::critical(this, "Error", "The captcha is NOT matched!");

        m_captcha = getCaptcha();

        CaptEdit.selectAll();
    }

    qDebug() << "LoginBtn_Clicked() End";
}

void QLoginDialog::CancelBtn_Clicked()
{
    qDebug() << "CancelBtn_Clicked() Begin";

    done(Rejected);

    qDebug() << "CancelBtn_Clicked() End";
}

QString QLoginDialog::getUser()
{
    return m_user;
}

QString QLoginDialog::getPwd()
{
    return m_pwd;
}

void QLoginDialog::Timer_Timeout()
{
    m_colors = getColors();

    update(); //每100ms改变颜色
}

void QLoginDialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    painter.fillRect(180, 100, 84, 24, Qt::white);//先画个白色矩形

    painter.setFont(QFont("Comic Sans MS", 12));

    for(int i=0; i<150; i++)
    {
        painter.setPen(m_colors[i%4]);
        painter.drawPoint(180 + qrand() % 84, 100 + qrand() % 24);//在矩形区域增加噪点
    }

    for(int i=0; i<4; i++)
    {
        painter.setPen(m_colors[i]);
        painter.drawText(180 + 20 * i, 100, 20, 24, Qt::AlignCenter, QString(m_captcha[i]));
    }
}

QString QLoginDialog::getCaptcha()
{
    QString ret = "";

    for(int i=0; i<4; i++)
    {
        int c = (qrand() % 2) ? 'a' : 'A';

        ret += static_cast<QChar>(c + qrand() % 26);
    }

    return ret;
}

Qt::GlobalColor* QLoginDialog::getColors()//随机产生颜色
{
    static Qt::GlobalColor colors[4];

    for(int i=0; i<4; i++)
    {
        colors[i] = static_cast<Qt::GlobalColor>(2 + qrand() % 16);//颜色范围2,17
    }

    return colors;
}

QLoginDialog::~QLoginDialog()
{

}

Widget源文件不变

5、小结

验证码用于有效避免恶意程序的破坏 

验证码的产生需要随机数的支持 

验证码必须附带有效噪点 

使用文本绘制的方式显示验证码 

每一个验证码的字符需要独立绘制 

 

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81941535