爲了不被惡意程序***,程序一般要使用安全機制。驗證碼機制是提供產生隨機驗證碼,由用戶識別填寫來判斷用戶有效性的安全機制。安全
驗證碼必須動態隨機產生,驗證碼的顯示必須避開使用標準組件(如標籤、文本框等),同時要增長足夠的障礙難度增長程序的識別難度。dom
基本的解決方案以下:ide
A、隨機產生目標驗證碼this
B、將驗證碼直接繪製於登陸對話框spa
C、驗證碼中的字符顏色隨機變化blog
D、在驗證碼區域隨機繪製噪點圖片
計算機只能產生僞隨機數。開發
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; }
每次繪製單個驗證碼,使用隨機顏色的畫筆get
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])); }
在驗證碼繪製矩形區域內隨機位置繪製噪點it
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 <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(); }
代碼見附件