zoukankan      html  css  js  c++  java
  • QT实现支持加密的Sqlite数据库引擎

      Sqlite数据库使用很广泛,我们经常会在发布一些小型软件的时候使用它,因为它不需要安装服务器。QT默认的数据库引擎是支持SQLITE数据库的,但并不支持对数据库加密,不加密的Sqlite数据库任何人都可以很轻易的打开它,这让我们的数据很不安全,很容易泄露或被篡改。自己对数据库进行加密当然也可以,但是那就不是通用的了,其他人用其他数据库工具也无法打开数据库文件,要想采用通用的加密方式,我们可以在网上找到sqlite3.dll这个动态库,这个动态库能够支持对Sqlite数据库文件加密。所以如果你想使用加密版的Sqlite,第一种方式就是直接使用sqlite3.dll里面的函数,这种方式简单,但是你就无法使用QT自带的数据库引擎了,这有很多缺点,用过QSqlDatabase的人应该知道,这个类可以打开很多种数据库类型,比如mysql,sqlserver,sqlite等,而且操作函数都是一致的,这使得我们在更换不同数据库时很方便,不需要做太大的改动,另外如果你不用QT默认的数据库引擎,那么就无法使用如QSqlQueryModel进行数据的展示了。

      那么有什么更好的方法吗?当然有,实际上QT给我们提供了一种方法,就是创建新的数据库引擎。而且要实现Sqlite非常简单,几乎可以用QT自带的文件做很小的修改就实现。下面我们来讲一下具体的操作。

    1.创建工程

    打开QtCreator,新建项目,选择Library,C++库。

    类型选择:Qt plugin,项目名称SQLITEEX

    类名:QSQLiteExDriverPlugin,基类选择:QSqlDriverPlugin,然后点击下一步完成创建。

    2.

    找到你安装QT的目录,将下面两个目录复制到工程目录下:

    D:\Program\Qt\Qt5.10.0\5.10.0\mingw53_32\include\QtCore\5.10.0\QtCore

    D:\Program\Qt\Qt5.10.0\5.10.0\mingw53_32\include\QtSql\5.10.0\QtSql

    然后在SQLITEEX.pro工程文件添加:

    INCLUDEPATH +=$$PWD/QtCore
    
    INCLUDEPATH +=$$PWD/QtSql
    

    3.

    下载sqlite3.dll,将sqlite3.lib和sliqte3.h文件放到工程目录下。将sqlite3.h添加到工程。

    然后在SQLITEEX.pro工程文件添加:

    LIBS += -L$$PWD -lsqlite3
    

    4.

    新建文件qsql_sqliteex_p.h,qsql_sqliteex.cpp。然后在QT源码下找到sqlite的实现源码,例如QT5.10在以下目录:

    D:\Program\Qt\Qt5.10.0\5.10.0\Src\qtbase\src\plugins\sqldrivers\sqlite

    找到qsql_sqlite_p.h文件,将#define QSQL_SQLITE_H#endif中间的内容复制到qsql_sqliteex_p.h,

    找到qsql_sqlite.cpp文件,将所有内容复制到qsql_sqliteex.cpp。然后将这两个文件中的类名做下修改:

    QSQLiteDriverPrivate修改为:QSQLiteExDriverPrivate

    QSQLiteDriver修改为QSQLiteExDriver

    QSQLiteResultPrivate修改为QSQLiteExResultPrivate

    QSQLiteResult修改为QSQLiteExResult

    5.修改QSQLiteExDriver::open

    找到QSQLiteExDriver::open函数,修改为内容:

    bool QSQLiteExDriver::open(const QString & db, const QString & user, const QString & password, const QString & host, int port, const QString & conOpts)
    {
        Q_D(QSQLiteExDriver);
        if (isOpen())
            close();
    
    
        int timeOut = 5000;
        bool sharedCache = false;
        bool openReadOnlyOption = false;
        bool openUriOption = false;
    #ifndef QT_NO_REGULAREXPRESSION
        static const QLatin1String regexpConnectOption = QLatin1String("QSQLITE3_ENABLE_REGEXP");
        bool defineRegexp = false;
        int regexpCacheSize = 25;
    #endif
    
        const auto opts = conOpts.splitRef(QLatin1Char(';'));
        for (auto option : opts) {
            option = option.trimmed();
            if (option.startsWith(QLatin1String("QSQLITE3_BUSY_TIMEOUT"))) {
                option = option.mid(20).trimmed();
                if (option.startsWith(QLatin1Char('='))) {
                    bool ok;
                    const int nt = option.mid(1).trimmed().toInt(&ok);
                    if (ok)
                        timeOut = nt;
                }
            } else if (option == QLatin1String("QSQLITE3_OPEN_READONLY")) {
                openReadOnlyOption = true;
            } else if (option == QLatin1String("QSQLITE3_OPEN_URI")) {
                openUriOption = true;
            } else if (option == QLatin1String("QSQLITE3_ENABLE_SHARED_CACHE")) {
                sharedCache = true;
            }
    #ifndef QT_NO_REGULAREXPRESSION
            else if (option.startsWith(regexpConnectOption)) {
                option = option.mid(regexpConnectOption.size()).trimmed();
                if (option.isEmpty()) {
                    defineRegexp = true;
                } else if (option.startsWith(QLatin1Char('='))) {
                    bool ok = false;
                    const int cacheSize = option.mid(1).trimmed().toInt(&ok);
                    if (ok) {
                        defineRegexp = true;
                        if (cacheSize > 0)
                            regexpCacheSize = cacheSize;
                    }
                }
            }
    #endif
        }
    
        int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
        openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
        if (openUriOption)
            openMode |= SQLITE_OPEN_URI;
    
        openMode |= SQLITE_OPEN_NOMUTEX;
    
        if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) {
            if(sqlite3_key(d->access,password.toUtf8(),password.toUtf8().length()) != SQLITE_OK)
            {
                if (d->access) {
                    sqlite3_close(d->access);
                    d->access = 0;
                }
                setLastError(qMakeError(d->access, tr("Error opening database by key"),
                             QSqlError::ConnectionError));
                setOpenError(true);
                return false;
            }
            sqlite3_busy_timeout(d->access, timeOut);
            setOpen(true);
            setOpenError(false);
    #ifndef QT_NO_REGULAREXPRESSION
            if (defineRegexp) {
                auto cache = new QCache<QString, QRegularExpression>(regexpCacheSize);
                sqlite3_create_function_v2(d->access, "regexp", 2, SQLITE_UTF8, cache, &_q_regexp, NULL,
                                           NULL, &_q_regexp_cleanup);
            }
    #endif
            return true;
        } else {
            if (d->access) {
                sqlite3_close(d->access);
                d->access = 0;
            }
    
            setLastError(qMakeError(d->access, tr("Error opening database"),
                         QSqlError::ConnectionError));
            setOpenError(true);
            return false;
        }
    }
    

     6.QSQLiteExDriverPlugin添加create函数

    QSQLiteExDriverPlugin类头文件添加公有函数:

    QSqlDriver* create(const QString &) Q_DECL_OVERRIDE;

     然后实现这个函数:

    QSqlDriver *QSQLiteExDriverPlugin::create(const QString &name)
    {
        if (name == QLatin1String("QSQLITEEX")) {
            QSQLiteExDriver* driver = new QSQLiteExDriver();
            return driver;
        }
        return 0;
    }
    

    7.修改SQLITEEX.json文件

    修改为:

    {
        "Keys" : [ "QSQLITEEX" ]
    }
    

    8.修改.pro文件

    Debug:TARGET = SQLITEEXD
    Release:TARGET = SQLITEEX
    TEMPLATE = lib
    CONFIG += plugin
    
    DESTDIR = ./plugin/sqldrivers
    

    9.到此修改完成,编译工程分别生成debug版的dll和release版的dll,注意发布的时候sqlite3.dll文件要放到exe目录下。

    10.创建测试工程

    (1)创建一个控制台程序,

    (2)添加代码

    #include <QCoreApplication>
    #include <QtSql/QtSql>
    #include <QPluginLoader>
    #include <iostream>
    using namespace std;
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    #ifdef QT_NO_DEBUG
      QPluginLoader driverload(qApp->applicationDirPath()+"/plugin/sqldrivers/SQLITEEX.dll");
    #else
      QPluginLoader driverload(qApp->applicationDirPath()+"/plugin/sqldrivers/SQLITEEXD.dll");
    #endif
        if(driverload.load())
        {
            QSqlDriverPlugin *plugin=qobject_cast<QSqlDriverPlugin*>(driverload.instance());
            if(plugin)
            {
                QSqlDriver *driver=plugin->create("QSQLITEEX");
                QSqlDatabase db;
                db=QSqlDatabase::addDatabase(driver);
                db.setDatabaseName("mydatabase.db");
                db.setPassword("123456");
                if(db.open())
                {
                    QSqlQuery qry(db);
                    qry.exec("create table t_trade(order_id varchar(100))");
                    qry.exec("insert into t_trade(order_id) values('10001')");
                    qry.exec("insert into t_trade(order_id) values('10002')");
                    qry.exec("select * from t_trade");
                    while(qry.next())
                    {
                        cout<<qry.value(0).toString().toStdString()<<endl;
                    }
                }
            }
            else
                cout<<"get plugin fail"<<endl;
        }
        else
            cout<<"driver load fail"<<endl;
        return a.exec();
    }
    

     (3)将plugin目录放到生成的exe目录下:

    (4)运行结果

    完整工程下载:https://download.csdn.net/download/jonahking2012/10688526

  • 相关阅读:
    190401装饰器-高阶函数-闭包
    190329迭代器-生成器-三元运算-列表解析
    OpenStack-Mitaka
    RabbitMQ
    190328文件处理
    190322函数
    190322字符串
    190321集合
    190320运算符&数据类型
    Zookeeper
  • 原文地址:https://www.cnblogs.com/WushiShengFei/p/9707244.html
Copyright © 2011-2022 走看看