用户权限管理
管理员,用户和组
管理员可以创建其他管理员、用户和组。非管理员的用户不能创建其他用户或组。
当 DolphinDB 集群第一次启动时,会自动创建一个管理员,用户 ID 为 “admin”,密码为 “123456”。”admin” 管理员具有所有的权限,并且不能被删除。其他管理员在刚创建时,是没有任何权限的,需要手动赋予他权限。
管理员可以赋予或禁止其他管理员/用户/组的权限,亦可撤销权限设置。
用户可以属于 0, 1 或多个组,把用户添加到组或把用户从组中移除会影响用户的访问权限。
权限类型
新创建的管理员、用户和组没有任何权限。超级管理员或其他具有管理员权限的用户可以使用 grant,deny 和 revoke 命令为非超级管理员的用户赋予权限、禁止权限,以及撤销权限设置,对应的权限状态为 Allow,Deny 和 None。
以下是 DolphinDB 支持的权限类型( accessType)、权限作用的范围(objs)和权限含义的详细表格。需要注意的是,如果运行在高可用环境下,并升级 server 到2.00.9版本,则需要手动为 admin 用户授予 DB_OWNER 权限:
accessType | objs(标量或向量) | 权限说明 | 注释 |
---|---|---|---|
TABLE_READ | 全局(*)、表(dfs://db/tb) | 读取所有/指定数据表 | |
TABLE_WRITE | 全局(*)、表(dfs://db/tb) | 写入所有/指定数据表,包含表数据的增删改权限 | |
TABLE_INSERT | 全局(*)、表(dfs://db/tb) | 追加数据到指定数据表 | 2.00.9/1.30.21 新增权限 |
TABLE_UPDATE | 全局(*)、表(dfs://db/tb) | 更新指定数据表的数据 | 2.00.9/1.30.21 新增权限 |
TABLE_DELETE | 全局(*)、表(dfs://db/tb) | 删除指定数据表的数据 | 2.00.9/1.30.21 新增权限 |
DBOBJ_CREATE | 全局(*)、库(dfs://db) | 在所有/指定数据库创建表 | |
DBOBJ_DELETE | 全局(*)、库(dfs://db) | 在所有/指定数据库删除表(包括数据和表结构) | |
DB_READ | 全局(*)、库(dfs://db) | 读某库所有表 | 2.00.9/1.30.21 新增权限 |
DB_WRITE | 全局(*)、库(dfs://db) | 写某库所有表,包含数据库所有表的增删改权限 | 2.00.9/1.30.21 新增权限 |
DB_INSERT | 全局(*)、库(dfs://db) | 追加数据到某库所有表 | 2.00.9/1.30.21 新增权限 |
DB_UPDATE | 全局(*)、库(dfs://db) | 更新数据到某库所有表 | 2.00.9/1.30.21 新增权限 |
DB_DELETE | 全局(*)、库(dfs://db) | 删除数据到某库所有表 | 2.00.9/1.30.21 新增权限 |
VIEW_EXEC | 全局(*)、视图(viewName) | 执行所有/指定视图 | |
DB_OWNER | 全局(*或不指定)、grant 时支持指定特定前缀的库(dfs://{dbPrefix}*) | 库:创建数据库/删除自己的数据库 表:创建/删除自己数据库下的表以及增加/删除表的分区、增加/删除表的列、更改表名。 权限:grant/revoke/deny 其他用户对自己创建数据库的以下权限:TABLE_READ, TABLE_WRITE, TABLE_INSERT, TABLE_UPDATE, TABLE_DELETE, DBOBJ_CREATE, DBOBJ_DELETE, DB_READ, DB_WRITE, DB_INSERT, DB_UPDATE, DB_DELETE |
|
DB_MANAGE | 全局(*或不指定)、库(dfs://db) | 赋予任意或指定数据库的管理权限,包括: 库:删除数据库 表:创建/删除/重命名数据表 分区:增加/删除分区 列:增加/删除/重命名/替换列 |
|
SCRIPT_EXEC | 全局(*或不指定) | 执行脚本 | |
TEST_EXEC | 全局(*或不指定) | 执行测试脚本 | |
QUERY_RESULT_MEM_LIMIT | 内存大小,单位为 GB | 限制用户的查询内存大小 | 2.00.9/1.30.21 新增权限,仅用于 grant 函数和 revoke 函数 |
TASK_GROUP_MEM_LIMIT | 内存大小,单位为 GB | 限制用户发送的批量子查询占用的内存大小 | 2.00.9/1.30.21 新增权限,仅用于 grant 函数和 revoke 函数 |
注意:
当用户创建定时作业(函数 scheduleJob)时,若作业中包含库/表的读写或修改操作,不需要具备相关的权限。但执行定时作业时,需要具备与对象相关的权限。
上述权限仅支持作用在分布式数据库。
兼容性说明:
1.30.15 版本后支持对用户赋予(grant)、禁止(deny)或撤销(revoke)共享内存表/共享流数据表/流数据引擎的读(TABLE_READ)或写(TABLE_WRITE)权限。
1.30.21 版本后:
新增了更细粒度的表权限(TABLE_INSERT/TABLE_UPDATE/TABLE_DELETE),以及库权限(DB_INSERT/DB_UPDATE/DB_DELETE)。
修改了 DB_MANAGE 的权限,不再支持创库,只支持对库进行 DDL 级别的操作管理,因此升级后需要重新赋予原 DB_MANAGE 用户 DB_OWNER 权限。
新增了权限类型 QUERY_RESULT_MEM_LIMIT,TASK_GROUP_MEM_LIMIT 用于约束用户查询内存的上限。
若对共享流数据表开启权限管理,需要注意:
在订阅节点,用户使用 subscribeTable 函数订阅流数据表之前,应当确认其是否具有流表的 TABLE_READ 权限。 没有 TABLE_READ 权限的用户不能订阅该流表。
在发布节点,若需要向共享流数据表写入数据,需要同时具有 TABLE_READ 和 TABLE_WRITE 的权限。
流表的发布端和订阅端不在同一个节点时,权限对象必须为 “nodeAlias:tableName”,比如:deny(`amy,TABLE_READ,”DFS_NODE1:st”), DFS_NODE1 为流数据表所在节点 Alias,st 为流数据表名。
只有流数据表的创建者或 admin 用户可以删除表。
当用户从一个流数据表中订阅数据存入数据表时,应当确保其有写入此数据表的权限。
权限确定规则
权限作用对象由高到底分为全局(*),数据库,表三个层级。
grant/revoke/deny 权限给某个对象时,系统会先检查是否存在更高层级的权限:
若不存在,则先 revoke 该层级下所有对象的原来的权限,再执行 grant/revoke/deny 操作。
若存在:
更高层级的权限为 “Allow”,则 grant/revoke 操作无效,deny 操作可以生效。
更高层级的权限为 “Deny”,则 grant/revoke/deny 的操作均无效。
例1:先设置表级权限,再设置库级权限:
deny(`userA, TABLE_READ, "dfs://testdb/pt")
grant(`userA, DB_READ, "dfs://testdb")
先执行 deny 禁止 userA 访问表 pt。再执行 grant 操作时,由于数据库 dfs://testdb
的权限层级大于数据表 pt
,因此:会先 revoke 数据库下所有表的读权限,原来 userA 对表 pt 的权限状态 “Deny” 将被清空;再赋予 userA 该数据库下所有表的读权限。因此 userA 对表 pt 的最终权限状态为 “Allow”。
例 2:先设置库级权限,再设置表级权限:
grant(`userA, DB_READ, "dfs://testdb")
revoke(`userA, TABLE_READ, "dfs://testdb/pt")
先执行 grant 允许 userA 访问数据库 dfs://testdb
下的所有表。再执行 revoke 操作时,由于已经存在一个库级的读权限,因此不能单独 revoke/allow 表的权限。因此 userA 对表 pt 的最终权限状态仍为 “Allow”。
若替换上述语句为:
grant(`userA, DB_READ, "dfs://testdb")
deny(`userA, TABLE_READ, "dfs://testdb/pt")
由于 deny 操作可以执行,最终 userA 对表 pt 的权限状态为 “Deny”, 对该数据库下其他分布式表的权限状态仍为 “Allow”。
若一个用户属于多个组,则用户的最终权限是个人权限(通过函数 getUserAccess 获取)和所属组权限(通过函数 getGroupAccess 获取)的共同决定的结果。
以用户 userA 对数据库 dfs://testdb
下的表 pt 的读权限为例:
系统遍历 userA 所属的用户组和 userA 个人的权限列表,检查在全局、数据库dfs://testdb
以及表 pt 上,是否存在状态为 “Deny” 的读权限 。
若存在 “Deny” 状态,则 userA 对表 pt 的最终权限状态为 “Deny”。
若不存在 “Deny” 状态,但存在 “Allow” 状态,则 userA 对表 pt 的最终权限状态为 “Allow”。
否则,userA 对表 pt 的最终权限状态为 “None”。
管理员通过 grant/revoke/deny 命令更改某个用户的权限后,该用户的权限会在重新登录账户或新的 session 中生效。
函数权限
只有管理员才能执行的权限函数如下:
赋权函数:deny, grant, revoke, addAccessControl
用户管理函数:resetPwd, createGroup, deleteGroup, createUser, deleteUser, addGroupMember, deleteGroupMember
此外部分运维函数也只能由管理员执行,具体请参考函数详情的说明。
DDL 和 DML 操作相关函数的权限校验
注意:下表中拥有 DB_OWNER 权限的用户必须为创建数据库或表的用户。
函数 | 权限(1.30.21/2.00.9以下版本) | 权限(1.30.21/2.00.9及以上版本) |
---|---|---|
database或createDB创建数据库 | DB_MANAGE, DB_OWNER | DB_OWNER |
database 加载已有的库 | 无校验 | 无校验 |
dropDatabase | DB_MANAGE, DB_OWNER | DB_MANAGE, DB_OWNER |
createTable | DBOBJ_CREATE, DB_OWNER | DBOBJ_CREATE, DB_OWNER, DB_MANAGE |
dropTable | DBOBJ_DELETE, DB_OWNER | DBOBJ_DELETE, DB_MANAGE, DB_OWNER |
createPartitionedTable | DB_MANAGE, DB_OWNER | DBOBJ_CREATE, DB_MANAGE, DB_OWNER |
renameTable | DBOBJ_DELETE, DB_OWNER | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DBOBJ_CREATE, DB_OWNER, DB_MANAGE |
loadTable | 自己创建的表,TABLE_READ, VIEW_EXEC | 自己创建的表,TABLE_READ, VIEW_EXEC |
addPartitions | DB_MANAGE, DB_OWNER | DB_MANAGE, DB_OWNER |
dropPartition | DBOBJ_DELETE, DB_OWNER | 指定参数 deleteSchema=false: DB_MANAGE, DB_OWNER, DB_DELETE, TABLE_DELETE(全局)<br> 指定参数 deleteSchema=true:DB_MANAGE, DB_OWNER |
addColumn | 自己创建的表,DBOBJ_CREATE | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DB_MANAGE, DB_OWNER, DBOBJ_CREATE |
dropColumns! | DB_MANAGE, DB_OWNER | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DB_MANAGE, DB_OWNER, DBOBJ_DELETE |
rename! | DB_MANAGE, DB_OWNER | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DBOBJ_CREATE, DB_OWNER, DB_MANAGE |
replaceColumn! | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DBOBJ_CREATE, DB_OWNER, DB_MANAGE | |
setColumnComment | 自己创建的表,DBOBJ_CREATE | 自己创建的表或拥有TABLE_READ权限,且拥有以下任一种权限:DB_MANAGE, DB_OWNER, DBOBJ_CREATE |
truncate | 自己创建的表,TABLE_WRITE, VIEW_EXEC | 自己创建的表,TABLE_WRITE, VIEW_EXEC |
upsert/SQL update | 自己创建的表,VIEW_EXEC | 自己创建的表,TABLE_WRITE, VIEW_EXEC |
SQL delete | 自己创建的表,TABLE_WRITE, VIEW_EXEC | 自己创建的表,TABLE_WRITE, VIEW_EXEC |
权限和函数可见性
相关函数 |
---|
getAllDBs |
getClusterDFSDatabases |
getDFSDatabases |
getDFSTablesByDatabase |
注意,这些函数的返回值受当前登录用户的权限影响:
若用户是管理员或者拥有 DB_MANAGE 权限,则可以看见当前节点所有数据库;
若用户拥有 DB_OWNER 权限,则可以看见当前节点该用户所创建的数据库;
例子
以管理员身份登录系统,并创建数据库 dfs://db1 以及其内的数据表 pt1。
$ login(`admin, `123456);
$ n=1000000
$ ID=rand(10, n)
$ x=rand(100, n)
$ t1=table(ID, x)
$ db=database("dfs://db1", HASH, [INT, 2]);
$ pt1 = db.createPartitionedTable(t1, `pt1, `ID)
$ pt1.append!(t1)
创建名为 “football” 的组,该组包含3个成员,分别是 EliManning、JoeFlacco 和 DeionSanders。该组的所有成员都可以读取 dfs://db1/pt1 表中的数据。用户 DeionSanders 可以删除数据库。
$ createUser(`EliManning, "AB123!@")
$ createUser(`JoeFlacco, "CD234@#")
$ createUser(`DeionSanders, "EF345#$")
$ createGroup(`football, `EliManning`JoeFlacco`DeionSanders)
$ grant(`football, TABLE_READ, "dfs://db1/pt1")
$ grant("DeionSanders", DB_MANAGE);
用户 EliManning 不可创建数据库:
$ login(`EliManning, "AB123!@");
$ db=database("dfs://db2", HASH, [INT, 2]);
$ db = database("dfs://db2", HASH, [4,2]) => Not granted to create or delete databases.
增加两个成员到 “football” 组中,并且把 JoeFlacco 从组中移除。使用 :doc:
/FunctionsandCommands/FunctionReferences/g/getUsersByGroupId
函数可以获取 “football” 组中的用户。
$ login(`admin, `123456);
$ createUser(`AlexSmith, "GH456$%")
$ createUser(`NickFoles, "IJ567%^")
$ addGroupMember(`AlexSmith`NickFoles, `football)
$ deleteGroupMember(`JoeFlacco, `football)
$ getUsersByGroupId(`football);
["AlexSmith","DeionSanders","EliManning","NickFoles"]
创建名为 “baseball” 的组,该组包含 3 个成员,分别是 CliffLee、ShoheiOhtani 和 DeionSanders。
$ createUser(`CliffLee, "GH456$%")
$ createUser(`ShoheiOhtani, "IJ567%^")
$ createGroup(`baseball, `CliffLee`ShoheiOhtani`DeionSanders)
DeionSanders 属于两个组。使用 getGroupsByUserId 函数可以获取 DeionSanders 所在的组。
$ getGroupsByUserId(`DeionSanders);
["football","baseball"]
进行以下权限设置:
$ grant(`baseball, DBOBJ_CREATE, "dfs://db1")
$ deny(`baseball, TABLE_READ, "dfs://db1/pt1")
$ deny(`baseball, DB_MANAGE);
“football” 组可以读取 dfs://db1/pt1 表,而 “baseball” 组被禁止了该权限。因此,DeionSanders 不具有该权限。
$ login(`DeionSanders, "EF345#$");
$ t = loadTable("dfs://db1","pt1");
t = loadTable("dfs://db1", "pt1") => Not granted to read table dfs://db1/pt1
尽管 DeionSanders 之前已经被赋予了删除数据库的权限,但是步骤4中的 “baseball” 组被禁止了该权限。DeionSanders 作为 “baseball” 组的一个成员,也被禁止了该权限。当 DeionSanders 不属于 “baseball” 组,或撤销禁止 “baseball” 组删除数据库的权限,或授予 “baseball” 组该权限时,用户 DeionSanders 才具有删除数据库的权限。
定义一个计算表 dfs://db1/pt1 行数的函数,将它定义为视图,并赋予 “baseball” 组执行该视图的权限。
$ login(`admin, `123456);
$ def countPt1(){
$ return exec count(*) from loadTable("dfs://db1","pt1")
$ }
$ addFunctionView(countPt1)
$ grant("baseball", VIEW_EXEC, "countPt1");
尽管 “baseball” 组没有读取表 dfs://db1/pt1 的权限,但是该组成员可以通过视图 countPt1 来获取表中的记录条数。以 ShoheiOhtani 身份登录,执行以下脚本:
$ login(`ShoheiOhtani, "IJ567%^");
$ countPt1();
1000000
定义一个函数,以计算表 dfs://db1/pt1 中 ID 为指定值的某列的最大值,将其定义为视图,并赋予 “baseball” 组执行该视图的权限。
$ login(`admin, `123456);
$ def getMax(column, idValue){
$ return exec max(column) from loadTable("dfs://db1","pt1") where id=idValue
$ }
$ addFunctionView(getMax)
$ grant("baseball", VIEW_EXEC, "getMax");
用户 CliffLee 可以登录并执行视图 getMax。
$ login(`CliffLee, "GH456$%")
$ getMax(x, 6);
99
管理员赋予用户 MitchTrubisky DB_OWNER 的权限:
$ login(`admin, `123456);
$ createUser(`MitchTrubisky, "JI3564^")
$ grant(`MitchTrubisky,DB_OWNER);
MitchTrubisky 创建数据表 dfs://dbMT/dt,并赋予用户 NickFoles 读取该数据表的权限:
$ login(`MitchTrubisky, "JI3564^");
$ db = database("dfs://dbMT", VALUE, 1..10)
$ t=table(1..1000 as id, rand(100, 1000) as x)
$ dt = db.createTable(t, "dt").append!(t)
$ grant(`NickFoles, TABLE_READ, "dfs://dbMT/dt");
用户 NickFoles 登录并读取 dfs://dbMT/dt 数据进行计算:
$ login(`NickFoles, "IJ567%^")
$ select max(x)-min(x) from loadTable("dfs://dbMT"gi, "dt");
99