版权声明:课程笔记内容整理于狄泰软件 https://blog.csdn.net/qq_39654127/article/details/81941535
1、第一个版本对话框
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、小结
验证码用于有效避免恶意程序的破坏
验证码的产生需要随机数的支持
验证码必须附带有效噪点
使用文本绘制的方式显示验证码
每一个验证码的字符需要独立绘制