温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

SQLite第四课 sqlite3_set_authoriz

发布时间:2020-06-01 20:54:10 来源:网络 阅读:406 作者:fengyuzaitu 栏目:数据库

例子说明
 可以将一个如下面格式的my_authorizer函数,注册到SQLite语句的解释执行语句当中,并且最先被执行,就像是一个钩子,对sql语句进行一些访问的控制,类似于网络数据包的netfilter。

代码
#include <iostream>
#include "sqlite/sqlite3.h"
using namespace std;
 
/*
该注册的回调函数,禁止用户删除任何的表,实际上,第三个参数
会传递进来当前操作的表的名称,可以通过和该值进行匹配,是否
需要对该表进行操作,当然由于pszString是一个无符号整型,如果
有多个参数想传递进来,可以设置sqlite3_set_authorizer的第三个
参数为结构体,然后通过将pszString进行类型的强制转换,返回
SQLITE_OK,表示继续执行,返回SQLITE_DENY表示拒绝执行
*/
int my_authorizer(void* pszString,
                  int nCode,/*当前SQL解析模块正在执行的操作码*/
                  const char* psz1,/*由SQL解析模块传递进来当前操作的数据库表,由操作码决定是否为空*/
                  const char* psz2,
                  const char* psz3,
                  const char* psz4)
{
  int nNotPermitCode = *(int*)pszString;
  if (nNotPermitCode == 11)
  {
    printf("can not execute drop\n");
    return SQLITE_DENY;
  } 
  return SQLITE_OK;
}
int main()
{
  int rc = 0;
  sqlite3* db = NULL;
  char* pdbName = "test0.db";
  char* pszErrMsg = NULL;
 
  rc = sqlite3_open_v2(pdbName,&db,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,NULL);
  
  char* pszCreateTb1 = "create virtual table geo_test1 using rtree_i32(id, minx, maxx)";
  rc = sqlite3_exec(db,pszCreateTb1, 0, 0, &pszErrMsg);
 
  char* pszInsertsql1 = "insert into geo_test1 values(1, 400, 400)";
  rc = sqlite3_exec(db,pszInsertsql1, 0, 0, &pszErrMsg);
 
  char* pszDropTable = "drop table geo_test1";
 
  /*
  授权动作编码(Authorizer Action Codes)
  摘自:https://www.sqlite.org/c3ref/c_alter_table.html
  每一种授权操作码都会传递不同的参数给授权注册函数,详细参考
  网址。11是删除数据库表的授权操作码,当调用授权注册函数的时候
  第三个字符串将获得当前被操作的表的名称。
  */
  int nNotPermitCode = 11;
  //第三个参数是传递给授权注册函数的参数值
  sqlite3_set_authorizer(db, my_authorizer, &nNotPermitCode);
  sqlite3_stmt* statement;
 
  rc = sqlite3_prepare_v2(db, pszDropTable, -1, &statement, NULL);

  //单步调试到perr的错误信息:no authored,表示无权操作
  const char* pszErr = sqlite3_errmsg(db);
  sqlite3_close(db);
  return 0;
}

原理分析
该文件包含了实现sliqte3_set_authorizer函数的代码。对于SQLite库来说,该功能
是可选的。嵌入式系统不需要该功能,可以通过预编译宏-DSQLITE_OMIT_AUTHORIZATION=1
来禁用该选项。实际上在VS的预编译选项中,添加SQLITE_OMIT_AUTHORIZATION即可!!
 
如果定义了SQLITE_OMIT_AUTHORIZATION宏,就会忽略该文件的所有代码
 
如下介绍两个重量级的函数:
int sqlite3_set_authorizer
(
 sqlite3 *db,
  int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
 void *pArg
)
设置或者清空访问授权函数
sqlite3_set_authorizer函数会将注册进来的授权函数的指针,传递给
数据库的句柄结构体sqlite3*db,并且也将该函数的第三个参数保存到句柄当中
千万不要想当然,句柄就是一个指针,可以指向一个结构体的指针。
实际上在这里有一个值得考虑的问题:如何防止死锁,一个锁她的最大范围
如何控制,在什么地方才需要真正的加锁!!
学习如何使用C语言,实现面向对象的编程思想,如何组织函数的处理结构
 
第三和第四个参数分别是当前正在访问的表名和列名,认证函数只能返回SQLITE_OK,SQLITE_DENY
SQLITE_IGNORE.如果返回SQLITE_OK,表示允许执行访问操作。SQLITE_DENY意味着SQL语句不会被执
行,sqlite3_exec函数将返回一个错误信息,SQLITE_IGNORE意味着SQL语句将被解析,但是尝试读
取,将返回空集合,尝试写将被忽略!!
 

/*
该函数被SQLite调用去执行注册进来的授权函数
根据给定的参数执行一个认证检测。返回值可以是SQLITE_OK或者SQLITE_IGNORE或者
SQLITE_DENY,如果返回SQLITE_DENY,pParse会携带修改的错误信息返回。
*/
int sqlite3AuthCheck(
  Parse *pParse,
  int code,
  const char *zArg1,
  const char *zArg2,
  const char *zArg3
){
  sqlite3 *db = pParse->db;
  int rc;

  /* Don't do any authorization checks if the database is initialising
  ** or if the parser is being invoked from within sqlite3_declare_vtab.
  */
  if( db->init.busy || IN_DECLARE_VTAB ){
    return SQLITE_OK;
  }

  if( db->xAuth==0 ){
    return SQLITE_OK;
  }
  rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
#ifdef SQLITE_USER_AUTHENTICATION
                 ,db->auth.zAuthUser
#endif
                );
  if( rc==SQLITE_DENY ){
    sqlite3ErrorMsg(pParse, "not authorized");
    pParse->rc = SQLITE_AUTH;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
    rc = SQLITE_DENY;
    sqliteAuthBadReturnCode(pParse);
  }
  return rc;
}


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI