利用函数视图实现精细化管控:DolphinDB 非标权限管理指南

1. 前言

DolphinDB 提供的用户权限管理功能管控的最小粒度是表级别,无法设置小于表粒度的数据访问权限管控,如限制用户仅能访问表中某些行或某些列的数据。为了满足客户更精细的权限管控需求,我们编写了本教程。

2. 概述

函数视图是封装了访问数据库以及相关计算语句的自定义函数,它提供了一种灵活的方式来控制用户访问数据库和表。用户即使不具备读写数据库原始数据的权限,也可通过执行函数视图,间接访问数据库,得到所需的计算结果。本教程主要介绍如何通过函数视图对表的访问权限实现更加精细和个性化的管控。

本教程中会学习到:

  • 如何在 DolphinDB 中用函数视图实现对表的访问权限实现更加精细和个性化的管控。
  • 如何实现授予某些用户或用户组对某个表只能访问某些行的权限:如授予用户 A 只能访问表1近1年的数据。
  • 如何实现授予某些用户或用户组对某个表只能访问某些列的权限:如授予用户 A 只能访问表1前10列的数据。
  • 如何实现授予某些用户或用户组对某个表只能访问某些行和列的权限:如授予用户 A 只能访问表1近1年的前10列的数据。

3. 测试环境准备

第一步:部署测试环境

  • 部署 DolphinDB 单节点:单节点部署教程。
  • 根据部署教程打开节点 web 编程界面,登陆后运行后续步骤测试代码,默认 admin 账户的密码是 123456。

图3-1 DolphinDB web 编程界面

第二步:创建模拟数据库表

创建本教程示例的分区表,模拟数据内容为:

  • 10年10支股票分钟级别指标,指标列为 col1, col2, col3, …, col49, col50。

粘贴下述代码至 web 编程界面,选中需要执行代码点击执行(执行快捷键:Ctrl+E)即可:

//登陆账户
login("admin", "123456")
//创建数据库和分区表
dbName = "dfs://stock"
tbName = "factor"
if(existsDatabase(dbName)){
	dropDatabase(dbName)
}
db = database(dbName, VALUE, 2023.01.01..2023.01.30)
colNames = `SecurityID`date`time`col1`col2`col3`col4`col5`col6`col7`col8`col9`col10`col11`col12`col13`col14`col15`col16`col17`col18`col19`col20`col21`col22`col23`col24`col25`col26`col27`col28`col29`col30`col31`col32`col33`col34`col35`col36`col37`col38`col39`col40`col41`col42`col43`col44`col45`col46`col47`col48`col49`col50
colTypes = [SYMBOL, DATE, SECOND, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE]
schema = table(1:0, colNames, colTypes)
db.createPartitionedTable(table=schema, tableName=tbName, partitionColumns='date')
//构建模拟数据
n = 1000000
SecurityID = rand(`000001`000002`000003`000004`000005`000006`000007`000008`000009`000010, n)
date = rand(2015.01.01..2024.12.31, n)
time = 09:30:00 + rand(331, n) * 60
factor = rand(10.0, n:50)
factor.rename!(`col1`col2`col3`col4`col5`col6`col7`col8`col9`col10`col11`col12`col13`col14`col15`col16`col17`col18`col19`col20`col21`col22`col23`col24`col25`col26`col27`col28`col29`col30`col31`col32`col33`col34`col35`col36`col37`col38`col39`col40`col41`col42`col43`col44`col45`col46`col47`col48`col49`col50)
t = table(SecurityID, date, time, factor)
//存入分区表
loadTable("dfs://stock", "factor").append!(t)

成功导入模拟数据后可以执行下述代码,查询前10行数据至内存中查看:

data = select top 10 * from loadTable("dfs://stock", "factor")

返回:

图3-2 部分模拟数据

第三步:创建测试用户

  • 创建用户 testUser1, testUser2。
  • 创建用户组 testGroup1,并将用户 testUser1 和 testUser2 加入该用户组。
login("admin", "123456")
createUser("testUser1", "123456",, false)
createUser("testUser2", "123456",, false)
createGroup("testGroup1", `testUser1`testUser2)

4. 设置行级别访问权限

4.1 限制用户仅能访问表中2023年以前的数据

行级别访问控制细则:

  • 限制用户仅能访问表中2023年以前的数据。
  • 限制用户单次访问不能超过1年的数据。
login("admin", "123456")
def getPre2023(startDate, endDate, cols="*", security=NULL) {
	if (endDate >= 2023.01.01) {
		throw("Not granted to read data after 2023")
	}
	if (startDate < temporalAdd(endDate, -1, "y")) {
		throw("Time duration exceeds 1 year. Please change the dates.")
	}
	whereConditions = [<date between startDate:endDate>]
	if (typestr(security) <> VOID) {
		whereConditions.append!(<SecurityID in security>)
	}
	return eval(sql(select=sqlCol(cols), from=loadTable("dfs://stock", "factor"), where=whereConditions))
}
addFunctionView(getPre2023)
grant("testUser1", VIEW_EXEC, "getPre2023")
  • 参数
    • startDateendDate 开始日期,结束日期,间隔不得超过1年。
    • cols 列名,默认所有列。
    • security 证券代码,默认所有证券代码。

  • 用户 testUser1 调用函数视图访问 2022 年指定证券、指定列的数据。
login("testUser1", "123456")
t = getPre2023(2022.01.01, 2022.12.31, `SecurityID`date`time`col1, `000001`000002)
  • 如果用户指定的日期不被允许访问,将会报错。
t = getPre2023(2022.12.01, 2023.01.31)
// output: Not granted to read data after 2023
  • 如果用户指定的起止日期间隔超过1年,将会报错。
t = getPre2023(2020.01.01, 2021.12.31)
// output: Time duration exceeds 1 year. Please change the dates.

4.2 限制用户仅能访问表中最近一年的数据

行级别访问控制细则:

  • 限制用户仅能访问表中最近一年的数据。
login("admin", "123456")
def getRecentYear(startDate=NULL, endDate=NULL, cols="*", security=NULL) {
	start = temporalAdd(date(now()), -1, "y")
	end = date(now())
	if (startDate == NULL) { date0 = start }
	else if (startDate < start) { throw("Not granted to read data before " + start) }
	else { date0 = startDate }
	if (endDate == NULL) { date1 = end }
	else if (endDate > end) { throw("Not granted to read data after " + end) }
	else { date1 = endDate }
	whereConditions = [<date between date0:date1>]
	if (typestr(security) <> VOID) {
		whereConditions.append!(<SecurityID in security>)
	}
	return eval(sql(select=sqlCol(cols), from=loadTable("dfs://stock", "factor"), where=whereConditions))
}
addFunctionView(getRecentYear)
grant("testUser2", VIEW_EXEC, "getRecentYear")
  • 参数
    • startDate 开始日期,默认1年前。
    • endDate 结束日期,默认今天。
    • cols 列名,默认所有列。
    • security 证券代码,默认所有证券代码。

  • 用户 testUser2 调用函数视图访问近1年所有数据。
login("testUser2", "123456")
t = getRecentYear()
  • 用户 testUser2 调用函数视图访问指定日期开始、指定列的数据。
login("testUser2", "123456")
t = getRecentYear(startDate=2023.07.01, cols=`SecurityID`date`time`col2`col3)
  • 如果用户指定的日期不被允许访问,将会报错。
t = getRecentYear(2023.01.01, 2023.12.31)
// output: Not granted to read data before 2023.03.08

5. 设置列级别访问权限

5.1 限制用户仅能访问表中前10列数据

列级别访问控制细则:

  • 限制用户仅能访问表中前10列的数据。
login("admin", "123456")
def getFirst10Col(startDate, endDate, cols=NULL, security=NULL) {
	grantedCols = loadTable("dfs://stock", "factor").schema()['colDefs']['name'][:10]
	notGranted = not(cols in grantedCols)
	if (typestr(cols) == VOID) { col = grantedCols }
	else if (sum(notGranted) > 0) {	throw("Not granted to read columns " + toStdJson(distinct(cols[notGranted]))) }
	else { col = cols }
	if (startDate < temporalAdd(endDate, -1, "y")) {
		throw("Time duration exceeds 1 year. Please change the dates.")
	}	
	whereConditions = [<date between startDate:endDate>]
	if (typestr(security) <> VOID) {
		whereConditions.append!(<SecurityID in security>)
	}
	return eval(sql(select=sqlCol(col), from=loadTable("dfs://stock", "factor"), where=whereConditions))
}
addFunctionView(getFirst10Col)
grant("testUser1", VIEW_EXEC, "getFirst10Col")
  • 参数
    • startDateendDate 开始日期,结束日期,间隔不得超过1年。
    • cols 列名,默认允许访问的所有列。
    • security 证券代码,默认所有证券代码。

  • 用户 testUser1 调用函数视图访问 2023 年指定证券、指定列的数据。
login("testUser1", "123456")
t = getFirst10Col(2023.01.01, 2023.12.31, `SecurityID`date`time`col5`col6`col7, `000008`000009`000010)
  • 如果用户指定的列不被允许访问,将会报错。
t = getFirst10Col(2023.01.01, 2023.12.31, `SecurityID`date`time`col40`col50)
// output: Not granted to read columns ["col50","col40"]

6. 设置行列级别访问权限

6.1 限制用户仅能访问表中2020年以后的几列数据

login("admin", "123456")
def getCond(startDate, endDate, cols=NULL, security=NULL) {
	grantedCols = `SecurityID`date`time`col46`col47`col48`col49`col50
	notGranted = not(cols in grantedCols)
	if (typestr(cols) == VOID) { col = grantedCols }
	else if (sum(notGranted) > 0) {	throw("Not granted to read columns " + toStdJson(distinct(cols[notGranted]))) }
	else { col = cols }
	if (startDate < 2020.01.01) {
		throw("Not granted to read data before 2020")
	}
	if (startDate < temporalAdd(endDate, -1, "y")) {
		throw("Time duration exceeds 1 year. Please change the dates.")
	}
	whereConditions = [<date between startDate:endDate>]
	if (typestr(security) <> VOID) {
		whereConditions.append!(<SecurityID in security>)
	}
	return eval(sql(select=sqlCol(col), from=loadTable("dfs://stock", "factor"), where=whereConditions))
}
addFunctionView(getCond)
grant("testGroup1", VIEW_EXEC, "getCond")
  • 参数
    • startDateendDate 开始日期,结束日期,间隔不得超过1年。
    • cols 列名,默认允许访问的所有列。
    • security 证券代码,默认所有证券代码。

  • 用户组 testGroup1 中的用户调用函数视图访问2021年指定列所有数据。
login("testUser2", "123456")
t = getCond(2021.01.01, 2021.12.31, `SecurityID`date`time`col47`col48`col49)
  • 如果用户指定的列不被允许访问,将会报错。
t = getCond(2021.01.01, 2021.12.31, `SecurityID`date`time`col44`col45`col46`col47)
// output: Not granted to read columns ["col45","col44"]
  • 如果用户指定的日期不被允许访问,将会报错。
t = getCond(2019.01.01, 2019.12.31, `SecurityID`date`time`col47`col48`col49)
// output: Not granted to read data before 2020

7. 函数视图运维介绍

7.1 添加函数视图

管理员定义函数后,使用 addFunctionView 函数添加函数视图。

login("admin", "123456")
def getCount() {
	return select count(*) from loadTable("dfs://stock", "factor")
}
addFunctionView(getCount)

7.2 删除函数视图

管理员使用 dropFunctionView 函数进行函数视图删除。删除函数视图后,所有被赋予该函数视图权限的用户将无法调用该函数视图。

login("admin", "123456")
dropFunctionView("getCount")

7.3 修改函数视图

管理员先删除函数视图,更改函数后,再添加函数视图。如删除前该函数视图已授权给其他用户,修改后需再次授权。

login("admin", "123456")
dropFunctionView("getCount")
go
def getCount() {
	return select count(*) from loadTable("dfs://stock", "factor") where date >= 2023.01.01
}
go
addFunctionView(getCount)

7.4 撤销用户权限

管理员撤销指定用户的函数视图执行权限后,该用户将无法调用该函数视图,但其他拥有该函数视图权限的用户不受影响。

login("admin", "123456")
revoke("testUser1", VIEW_EXEC, "getPre2023")

8. 常见问题解答(FAQ)

8.1 The FunctionView [xxx] already exists, please drop it before adding a new one

执行 addFunctionView 函数添加新的函数视图时报如下错误:

addFunctionView(getCount) => The FunctionView [getCount] already exists, please drop it before adding a new one

造成问题原因:

  • 已经有同名的函数视图,导致本次添加失败后报错终止任务。

解决方案:

  • 办法1:通过 dropFunctionView 函数 删除已定义的同名函数视图
dropFunctionView("getCount")
  • 方法2:通过 try-catch 语句捕获错误日志并打印,避免因为此行代码导致运行终止
try{addFunctionView(getCount)} catch(ex){print(ex)}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/611763.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓通信方式简介

目录 一、Binder二、Socket三、Binder与Socket四、Handler 一、Binder Binder作为Android系统提供的一种IPC机制&#xff0c;无论从系统开发还是应用开发&#xff0c;都是Android系统中最重要的组成。 二、Socket Socket通信方式也是C/S架构&#xff0c;比Binder简单很多。在…

数据库开启远程连接

服务器端添加一个允许远程连接的root用户: mysql -u root -p create user root192.168.10.20 identified by admin; //创建一个192.168.10.20地址远程连接的root用户 grant all privileges on *.* to root192.168.10.20; //赋予远程root用户所有的权…

Linux文本处理工具【tr、cut、sort、uniq】

1. tr 命令——替换、压缩、删除 tr (Text Replacer) 命令常用来对来自标准输入的字符进行替换、压缩和删除。 命令格式 &#xff1a;tr [选项]... SET1 [SET2] &#xff08;SET 是一组字符串&#xff0c;一般都可按照字面含义理解&#xff09; 选项&#xff1a; -d 删除 -s 压…

01面向类的讲解

指针指向类成员使用 代码&#xff1a; #include<iostream> using namespace std;class Test { public:void func() { cout << "call Test::func" << endl; }static void static_func();int ma;static int mb; //不依赖对象 }; void Test::static…

DDS Blockset Shapes Demo

此示例演示DDS模块集Blockset形状演示应用程序。Shapes Demo是一个常见的数据分发服务&#xff08;DDS&#xff09;应用程序&#xff0c;用于介绍DDS概念&#xff0c;你可以使用它发布和订阅以简单形状&#xff08;圆形、方形和三角形&#xff09;表示的主题&#xff0c;并观察…

如何设计测试用例

一、介绍 测试用例就是一个文档&#xff0c;描述输入、动作、或者时间和一个期望的结果&#xff0c;其目的是确定应用程序的某个特性是否正常的工作。 二、基本格式 用例的基本要素包括测试用例编号、测试标题、重要级别、测试输入、操作步骤、预期结果等。 用例编号&#…

适合年轻人的恋爱交友脱单软件有哪些?中国十大社交软件排行榜分享

交友始祖&#xff1a;Tinder 一直很受欢迎&#xff0c;可以向上扫给 super like (每日有一次免费机会)。如果双方互相 like&#xff0c;代表配对成功&#xff0c;就可以开始聊天。另外&#xff0c;每日有 10 个 top picks 供选择&#xff0c;你可以免费选一位 主力编外&#xf…

添加一个索引要投产,需要哪些步骤?

编程一生 致力于写大家都能看懂的、有深度的 技术文章 05/2024 01 开场白 亚马逊有个bar raiser文化。就是说新招来的人一定要超过之前入职人员的平均水平&#xff0c;宁缺毋滥。越来越多的公司在推行这种文化。在这种氛围下&#xff1a;“虽然我不懂&#xff0c;但是活儿是能出…

一文了解webpack和vite中Tree-Shaking

1、什么是Tree-Shaking 1.1 摇树优化&#xff08;Tree Shaking&#xff09;是Webpack中一种用于优化JavaScript代码的技术。它的目标是通过静态分析&#xff0c;从代码中剔除未被使用的模块&#xff0c;从而减少最终打包文件的大小。 1.2 Tree-shaking 它的名字来源于通过摇晃…

纯血鸿蒙APP实战开发——数字滚动动效实现

介绍 本示例主要介绍了数字滚动动效的实现方案。 该方案多用于数字刷新&#xff0c;例如页面刷新抢票数量等场景。 效果图预览 使用说明&#xff1a; 下拉页面刷新&#xff0c;数字进行刷新。 实现思路 通过双重ForEach循环分别横向、纵向渲染数字。 Row() {ForEach(this…

基于SSM的文化遗产的保护与旅游开发系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的文化遗产的保护与旅游开发系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…

Java中包的概念package

Package Package:包 指明方法、类所处的包&#xff1b; 将类分配到不同的包中&#xff0c;方便管理&#xff1b; 用于指明文件中定义的类、接口等结构所在的包&#xff1b; 一个源文件只要一个包的声明语句&#xff0c;必须放到开头&#xff1b; 属于标识符&#xff0c;满足命…

Java类加载器介绍

在Java中&#xff0c;类加载器是一种动态加载类的机制&#xff0c;它负责在运行时查找、加载和链接类文件。当Java应用程序需要创建某个类的对象时&#xff0c;类加载器会在运行时查找该类对应的.class文件&#xff0c;并将其加载到Java虚拟机中。Java类加载器通常分为三层&…

《ESP8266通信指南》15-MQTT连接、订阅MQTT主题并打印消息(基于Lua|适合新手|非常简单)

往期 《ESP8266通信指南》14-连接WIFI&#xff08;基于Lua&#xff09;-CSDN博客 《ESP8266通信指南》13-Lua 简单入门&#xff08;打印数据&#xff09;-CSDN博客 《ESP8266通信指南》12-Lua 固件烧录-CSDN博客 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP826…

空间复杂度

前言 通过上一节的学习&#xff0c;我们知道了衡量一个算法是否高效的标准就是复杂度&#xff0c;我们已经学习了时间复杂度&#xff0c;那么本节我们就了解一下空间复杂度的相关知识&#xff0c;那么我们废话不多说&#xff0c;正式进入今天的学习 空间复杂度 空间复杂度也是…

Bugku Crypto 部分题目简单题解(三)

where is flag 5 下载打开附件 Gx8EAA8SCBIfHQARCxMUHwsAHRwRHh8BEQwaFBQfGwMYCBYRHx4SBRQdGR8HAQ0QFQ 看着像base64解码 尝试后发现&#xff0c;使用在线工具无法解密 编写脚本 import base64enc Gx8EAA8SCBIfHQARCxMUHwsAHRwRHh8BEQwaFBQfGwMYCBYRHx4SBRQdGR8HAQ0QFQ tex…

机器学习——6.模型训练案例: 预测儿童神经缺陷分类TD/ADHD

案例目的 有一份EXCEL标注数据&#xff0c;如下&#xff0c;训练出合适的模型来预测儿童神经缺陷分类。 参考文章&#xff1a;机器学习——5.案例: 乳腺癌预测-CSDN博客 代码逻辑步骤 读取数据训练集与测试集拆分数据标准化数据转化为Pytorch张量label维度转换定义模型定义损…

MySQL慢查询SQL优化

一、慢查询日志 描述&#xff1a;通过慢查询日志等定位那些执行效率较低的SQL语句 查看 # 慢查询是否开启 show variables like slow_query_log%; # 慢查询超时时间 show variables like long_query_time%;执行SQL 开启慢查询日志 set global slow_query_log ON;设置慢查…

Secure Transformer Inference Made Non-interactive

目录 1.概述2.Attention2.1 Matrix multiplication (ciphertext-plaintext).2.2 Matrix multiplication (ciphertext-ciphertext)2.3 Placement of bootstrapping3.SIMD密文压缩和解压缩4.SIMD槽折叠5.实验结果 1.概述 我们提出了NEXUS&#xff0c;这是第一个用于安全变压器推…

pdf编辑软件,四款软件让你轻松玩转PDF编辑!

在信息爆炸的当今时代&#xff0c;PDF格式文档因其跨平台、不易被篡改的特性而深受大家喜爱。然而&#xff0c;如何高效地编辑PDF文档却成为许多人的难题。今天&#xff0c;我将为大家推荐四款实用的PDF编辑软件&#xff0c;让你轻松玩转PDF编辑&#xff0c;告别繁琐操作&#…