QT开发(六十六)——登录对话框的验证机制

一、验证码机制

为了避免被恶意程序攻击,程序通常要使用安全机制。验证码机制是提供产生随机验证码,由用户识别填写来判断用户有效性的安全机制。

验证码必须动态随机产生,验证码的显示必须避开使用标准组件(如标签、文本框等),同时要增加足够的障碍难度增加程序的识别难度。

基本的解决方案如下:

A、随机产生目标验证码

B、将验证码直接绘制于登录对话框

C、验证码中的字符颜色随机变化

D、在验证码区域随机绘制噪点

二、登录对话框验证码机制实现

1、随机数产生

计算机只能产生伪随机数。

QString getRandom()
{
    QString ret = "";
    for(int i=0; i<4; i++)
    {
        int c = (qrand() % 2) ? 'a' : 'A';
        
        ret += static_cast<QChar>(c + qrand() % 26);
    }
    return ret;
}

2、验证码绘制

每次绘制单个验证码,使用随机颜色的画笔

for(int i = 0; i < 4; i++)
    {
        painter.setPen(m_colors[i]);
        painter.drawText(245 + 25*i, 150, 25, 30, Qt::AlignCenter, QString(m_verification[i]));
    }

3、噪点绘制

在验证码绘制矩形区域内随机位置绘制噪点

for(int i=0; i<150; i++)
    {
        painter.setPen(m_colors[i%4]);
        painter.drawPoint(245 + qrand() % 99, 150 + qrand() % 29);
    }

4、代码实例

    LoginDialog.h文件:

#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H
 
#include <QDialog>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QTimer>
 
class LoginDialog: public QDialog
{
    Q_OBJECT
private:
    QLabel UserLabel;
    QLabel PwdLabel;
    QLabel Verification;
    QLineEdit VerificationEdit;
    QLineEdit UserEdit;
    QLineEdit PwdEdit;
    QPushButton B_Login;
    QPushButton B_Cancel;
    QString m_user;
    QString m_pwd;
    Qt::GlobalColor* m_colors;
    QString m_verification;
    QTimer m_timer;
private:
    Qt::GlobalColor* getColors();
    QString getVerificationCode();
    void paintEvent(QPaintEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
 
private slots:
    void Login();
    void Cancel();
    void onTimeOut();
 
public:
    LoginDialog(QWidget *parent);
    QString getUser();
    QString getPwd();
    ~LoginDialog();
};
 
#endif // LOGINDIALOG_H

    LoginDialog.cpp文件:

#include "LoginDialog.h"
#include <QDebug>
#include <QMessageBox>
#include <QPainter>
#include <QMouseEvent>
#include <QTime>
 
 
LoginDialog::LoginDialog(QWidget *parent)
    :QDialog(parent, Qt::WindowCloseButtonHint), UserLabel(this), PwdLabel(this),Verification(this),
      VerificationEdit(this), UserEdit(this), PwdEdit(this), B_Login(this),B_Cancel(this)
{
    UserLabel.setText("User ID:");
    UserLabel.move(50, 50);
    UserLabel.resize(60, 30);
 
    UserEdit.move(110, 50);
    UserEdit.resize(200, 30);
 
    PwdLabel.setText("Password:");
    PwdLabel.move(50, 100);
    PwdLabel.resize(60,30);
 
    PwdEdit.move(110, 100);
    PwdEdit.resize(200, 30);
    PwdEdit.setEchoMode(QLineEdit::Password);
 
    Verification.move(50, 150);
    Verification.resize(110, 30);
    Verification.setText("Verification Code: ");
 
    VerificationEdit.move(160, 150);
    VerificationEdit.resize(80, 30);
 
    B_Login.setText("Login");
    B_Login.move(110, 200);
    B_Login.resize(80, 30);
 
    B_Cancel.setText("Cancel");
    B_Cancel.move(230, 200);
    B_Cancel.resize(80, 30);
 
    setWindowTitle("Login Window");
    setFixedSize(400, 300);
    //生成伪随机种子
    qsrand(QTime::currentTime().second() * 1000 + QTime::currentTime().msec());
    m_colors = getColors();
    m_verification = getVerificationCode();
 
    connect(&B_Login, SIGNAL(clicked()), this, SLOT(Login()));
    connect(&B_Cancel, SIGNAL(clicked()), this, SLOT(Cancel()));
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
    m_timer.start(500);
}
 
void LoginDialog::onTimeOut()
{
    qsrand(QTime::currentTime().second() * 1000 + QTime::currentTime().msec());
    m_colors = getColors();
    update();
}
 
QString LoginDialog::getUser()
{
    return m_user;
}
 
QString LoginDialog::getPwd()
{
    return m_pwd;
}
 
void LoginDialog::Login()
{
    qDebug() << "login";
    QString verif = VerificationEdit.text().replace(" ", "");
    if(m_verification.toLower() == verif.toLower())
    {
        m_user = UserEdit.text().trimmed();
        m_pwd = PwdEdit.text();
        if(!(m_user.isEmpty() || m_pwd.isEmpty()))
        {
            done(Accepted);
        }
        else
        {
            QMessageBox mb(this);
            mb.setWindowTitle("Warning Message");
            mb.setIcon(QMessageBox ::Warning);
            mb.setText("User or PassWord can't empty! \nPlease check your username or password!");
            mb.setStandardButtons(QMessageBox::Ok);
            mb.exec();
        }
    }
    else
    {
        QMessageBox::critical(this, "Verification Code Error", "Verification Code Error!\nPlease Enter Again.", QMessageBox::Ok);
        VerificationEdit.selectAll();
    }
}
 
void LoginDialog::Cancel()
{
    qDebug() << "cancel";
    done(Rejected);
 
}
 
void LoginDialog::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    //填充验证码绘制矩形
    painter.fillRect(245, 150, 100, 30, Qt::white);
    painter.setFont(QFont("Comic Sans MS", 12));
    //绘制验证码
    for(int i = 0; i < 4; i++)
    {
        painter.setPen(m_colors[i]);
        painter.drawText(245 + 25*i, 150, 25, 30, Qt::AlignCenter, QString(m_verification[i]));
    }
    //绘制噪点
    for(int i=0; i<150; i++)
    {
        painter.setPen(m_colors[i%4]);
        painter.drawPoint(245 + qrand() % 99, 150 + qrand() % 29);
    }
}
 
Qt::GlobalColor* LoginDialog::getColors()
{
    static Qt::GlobalColor colors[4];
    for(int i=0; i<4; i++)
    {
        colors[i] = static_cast<Qt::GlobalColor>(2 + qrand() % 16);
    }
    return colors;
}
//获取验证码
QString LoginDialog::getVerificationCode()
{
    QString ret = "";
    for(int i = 0; i < 4; i++)
    {
        int c = (qrand() % 2) ? 'a' : 'A';
        ret += static_cast<QChar>(c + qrand() % 26);
    }
    return ret;
}
//双击验证码绘制矩形区域,生成新的验证码
void LoginDialog::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(QRect(245, 150, 100, 30).contains(event->pos()))
    {
        m_verification = getVerificationCode();
        repaint();
    }
}
 
LoginDialog::~LoginDialog()
{
}

    Main.cpp文件:

#include "Widget.h"
#include <QApplication>
#include "LoginDialog.h"
#include <QDebug>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    LoginDialog dialog(&w);
 
    dialog.show();
    if(dialog.exec() == QDialog::Accepted)
    {
        qDebug() <<"User:" << dialog.getUser();
        qDebug() << "PassWord:" << dialog.getPwd();
    }
    return a.exec();
}

 QT开发(六十六)——登录对话框的验证机制_开发

代码见附件