为了避免被恶意程序攻击,程序通常要使用安全机制。验证码机制是提供产生随机验证码,由用户识别填写来判断用户有效性的安全机制。
验证码必须动态随机产生,验证码的显示必须避开使用标准组件(如标签、文本框等),同时要增加足够的障碍难度增加程序的识别难度。
基本的解决方案如下:
A、随机产生目标验证码
B、将验证码直接绘制于登录对话框
C、验证码中的字符颜色随机变化
D、在验证码区域随机绘制噪点
计算机只能产生伪随机数。
QString getRandom(){ QString ret = ""; for(int i=0; i<4; i++) { int c = (qrand() % 2) ? 'a' : 'A'; ret += static_cast(c + qrand() % 26); } return ret;}
每次绘制单个验证码,使用随机颜色的画笔
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); }
LoginDialog.h文件:
#ifndef LOGINDIALOG_H#define LOGINDIALOG_H #include #include #include #include #include class LoginDialog: public QDialog{ Q_OBJECTprivate: 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 #include #include #include #include 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(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(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 #include "LoginDialog.h"#include 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();}
650) this.width=650;" src="https://s4.51cto.com/wyfs02/M01/8C/AC/wKioL1h0Z8bR8meBAABNlyr5C-Y949.png" title="图片1.png" alt="wKioL1h0Z8bR8meBAABNlyr5C-Y949.png" />
代码见附件
本文出自 “生命不息,奋斗不止” 博客,谢绝转载!