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();
}
代码见附件
转载于:https://blog.51cto.com/9291927/1890686