联 系 我 们
售前咨询
售后咨询
微信关注:星环科技服务号
更多联系方式 >
6.6.5.2 管理行/列级权限
更新时间:10/24/2023, 7:20:26 AM

针对数据敏感的场景,例如希望各银行的用户只能查询到各自分行的数据,不希望展示某些列(如电话号)的数据,此时可为指定的表授予行/列级权限,最大限度满足企业多样的数据管控需求,保护数据访问安全性。

本文介绍如何通过 SQL 命令的方式管理行/列级权限,此外,您还可以通过页面直观地配置库、表、列级权限。

行/列级与表级权限说明
类别 说明

表权限(PRIVILEGE)

限制执行 SELECTINSERTUPDATEDELETE 操作。

行权限(PERMISSION)

限制表级的 SELECTUPDATEDELETE 操作对指定行生效。

列权限(PERMISSION)

限制表级的 SELECT 操作对指定列生效。

您需要为用户授予表级权限,行/列级权限设置才有意义,例如某用户没有表 A 的 SELECT 权限,那么为其授予行级 SELECT 权限也依旧无法读取表 A 的数据。

INSERT 操作不受行/列级权限限制,此外,由于行级权限没有“行 Owner” 的概念,不会自动继承行级权限,例如用户插入了一条数据,在对其执行 SELECTUPDATEDELETE 操作时依然受控于行权限约束。

SQL 语法及使用示例

执行本文介绍的 SQL 命令前,您需要以 ADMIN 角色或表 Owner 的身份连接数据库。

设置行级权限

语法

GRANT PERMISSION ON TABLE <table_name> FOR ROWS <where_clause>;
复制

说明:<where_clause> 为一个where字句。

示例一:授予行权限给用户

在本示例中,我们在表中新建一个用户列(username),将每行记录的 username 值设为对该行记录有权限的用户,然后结合 context 函数,即可实现只有当前用户(current_user)和 username 的值相匹配时才能对记录进行操作。

本示例中,我们使用的表为 finances_holo,其完整数据如下:

+------+---------+-----------+
| eid  |  funds  | username  |
+------+---------+-----------+
| 001  | 500.0   | alice     |
| 002  | 500.0   | bob       |
| 003  | 1000.0  | alice     |
| 004  | 2000.0  | carol     |
+------+---------+-----------+
复制
  1. 以 ADMIN 角色或表 Owner 的身份连接数据库,执行下述操作即可在实现上述需求,同时我们授予 ADMIN 角色对所有记录拥有操作权限。

    GRANT PERMISSION ON TABLE finances_holo FOR ROWS WHERE username = CURRENT_USER() OR HAS_ROLE('admin');
    复制
  2. 查看行级权限已开启,如下所示。

    > SHOW PERMISSION ON TABLE finances_holo;
    +-------------+-------------------------------------------------------+
    | row/column  |                      definition                       |
    +-------------+-------------------------------------------------------+
    | ROWS        | WHERE username = CURRENT_USER() OR HAS_ROLE('admin')  |
    +-------------+-------------------------------------------------------+
    复制
  3. (可选)验证用户权限。

    上述授权操作并不会为用户赋予表级权限,例如某用户本身不具备对 finances_holo 表的 SELECT 权限,那么他也无法读取到数据。接下来,我们以 alice 用户为例,演示其在不同表权限下的数据读写情况。

    • 场景一:alice 拥有表的 SELECT/INSERT/UPDATE/DELETE 权限时。

      执行 SELECT 操作查看所有记录时,只会展示 username 值为 alice 的记录。

      > SELECT * FROM finances_holo;
      +------+---------+-----------+
      | eid  |  funds  | username  |
      +------+---------+-----------+
      | 003  | 1000.0  | alice     |
      | 001  | 500.0   | alice     |
      +------+---------+-----------+
      复制

      执行 UPDATE/DELETE 操作,只会对上述两条记录生效,以 UPDATE 操作为例,如下所示。

      INSERT 权限不受行级权限影响。

      > UPDATE finances_holo SET funds = 800 WHERE eid = "001";
      1 row affected (0.711 seconds)
      
      > SELECT * FROM finances_holo;
      +------+---------+-----------+
      | eid  |  funds  | username  |
      +------+---------+-----------+
      | 003  | 1000.0  | alice     |
      | 001  | 800.0   | alice     |
      +------+---------+-----------+
      2 rows selected (1.68 seconds)
      复制
    • 场景二:alice 不具备 finances_holo 表的任何权限。

      以执行 SELECT 操作查看数据为例,ArgoDB 将返回无权限提示信息。

      > SELECT * FROM finances_holo;
      Error: COMPILE FAILED: Internal error HiveAccessControlException: [Error 20388] Permission denied: Principal [name=alice, type=USER] does not have following privileges for operation QUERY [[SELECT] on Object [type=TABLE_OR_VIEW, name=demodata.finances_holo]] (state=42000,code=20388)
      复制
示例二:使用辅助表设置行级权限

本示例中,我们希望安装用户所在的分支银行对 finances_new 表授予行级权限,即用户只能看到其所属支行的数据。

首先,我们为表新增一个支行列(branch),将每行记录的 username 值设置为对该行记录有权限的 支行名称,然后通过一个辅助表来记录用户与支行的对应关系,在行级权限设置时,通过该表过滤出有权限的用户。

本示例中,我们使用了两个表,分别是:

  • finances_new:完整数据如下。

    +------+---------+---------+
    | eid  |  funds  | branch  |
    +------+---------+---------+
    | 001  | 500.0   | A       |
    | 002  | 500.0   | A       |
    | 003  | 1000.0  | A       |
    | 004  | 2000.0  | B       |
    +------+---------+---------+
    复制
  • branch_assignment(辅助表),记录了用户与支行的关系,完整数据如下。

    > SELECT * FROM branch_assignment;
    +-----------+---------+
    | username  | branch  |
    +-----------+---------+
    | bob       | A       |
    | alice     | A       |
    | carol     | B       |
    +-----------+---------+
    复制
    1. 以 ADMIN 角色或表 Owner 的身份连接数据库,执行下述操作即可在实现上述需求,同时我们授予 ADMIN 角色对所有记录拥有操作权限。

      GRANT PERMISSION ON TABLE finances_new FOR ROWS WHERE branch = (SELECT branch FROM branch_assignment WHERE username = CURRENT_USER()) OR HAS_ROLE('ADMIN');
      复制

      为保障权限判断运行正常,我们为用户授予了 branch_assignment 表的 SELECT 权限。

    2. 执行 SHOW PERMISSION ON finances_new; 命令可查看行级权限已开启。

    3. (可选)验证用户权限。

      假设我们已经为不同支行的用户授予了 finances_new 表的 SELECT 权限,接下来,我们以 alice 和 carol 用户为例,演示其数据读取情况。

      • 以 alice 身份连接 ArgoDB 数据库,只能看到 A 支行的数据。

        > SELECT * FROM finances_new;
        +------+---------+---------+
        | eid  |  funds  | branch  |
        +------+---------+---------+
        | 001  | 500.0   | A       |
        | 002  | 500.0   | A       |
        | 003  | 1000.0  | A       |
        +------+---------+---------+
        复制
      • 以 carol 身份连接 ArgoDB 数据库,只能看到 B 支行的数据。

        > SELECT * FROM finances_new;
        +------+---------+---------+
        | eid  |  funds  | branch  |
        +------+---------+---------+
        | 004  | 2000.0  | B       |
        +------+---------+---------+
        复制
撤销行级权限设置

语法

REVOKE PERMISSION ON TABLE <table_name> FOR ROWS;
复制

<table_name>更换为目标表名,执行该语句将撤销对指定表的行级权限设置。

示例

  1. 以 ADMIN 角色或表 Owner 的身份连接数据库,查看 finances_holo 表的行级权限设置。

    SHOW PERMISSION ON TABLE finances_holo;
    +-------------+-------------------------------------------------------+
    | row/column  |                      definition                       |
    +-------------+-------------------------------------------------------+
    | ROWS        | WHERE username = CURRENT_USER() OR HAS_ROLE('admin')  |
    +-------------+-------------------------------------------------------+
    复制
  2. 撤销行级权限设置,随后查看权限设置已清空。

    > REVOKE PERMISSION ON TABLE finances_holo FOR ROWS;
    No rows affected (0.115 seconds)
    
    > SHOW PERMISSION ON TABLE finances_holo;
    +-------------+-------------+
    | row/column  | definition  |
    +-------------+-------------+
    +-------------+-------------+
    复制
设置列级权限

语法

GRANT PERMISSION ON [TABLE] <table_name> FOR COLUMN <case_when>;
复制

这里的 <case_when_clause> 为一个 CASE WHEN 条件函数

使用示例

假设我们有一个银行用户信息表(bank_account),其完整数据如下。

+--------+---------------------+------------------+
|  name  |         id          |      email       |
+--------+---------------------+------------------+
| jack   | 511702198907108849  | jack@126.com     |
| alice  | 530724198511061294  | alice@gmail.com  |
| tom    | 320702199203128764  | tom@outlook.com  |
| amy    | 440183198811183889  | amy@qq.com       |
+--------+---------------------+------------------+
复制

为保障信息安全,我们希望只有 ADMIN 用和表 Owner 可查看完整数据,对普通的业务用户只展示脱敏后的数据,具体如下:

  • name 列:只显示第一个字符,其他隐藏为星号。

  • id 列:只显示前三位,后四位,其他隐藏。

  • email 列:邮箱的用户仅显示第一个字母,其余隐藏为星号,同时可正常展示邮箱域名。

    1. 以 ADMIN 角色或表 Owner 的身份连接数据库,执行下述命令为 normal_user 和 hive 用户授予 bank_account 表的 SELECT 权限。

      GRANT SELECT ON bank_account TO USER hive, USER normal_user;
      复制
    2. 依次执行下述命令,完成列级权限设置。

      -- 当用户角色不为 ADMIN 时,只显示 name 列的第一个字符,其他隐藏为星号;
      GRANT PERMISSION ON bank_account
      FOR COLUMN name CASE WHEN HAS_ROLE('ADMIN')
      THEN name ELSE MASK(name, 1) END;
      复制
      -- 当用户角色不为 ADMIN 时,只显示 id 列的前三位,后四位,其他隐藏为星号;
      GRANT PERMISSION ON bank_account
      FOR COLUMN id CASE WHEN HAS_ROLE('ADMIN')
      THEN id ELSE MASK(id, 3, 4) END;
      复制
      -- 当用户角色不为 ADMIN 时,只显示 email 列邮箱前缀的第一个字母,前缀的其他字母隐藏为星号,邮箱域名显示。
      GRANT PERMISSION ON bank_account
      FOR COLUMN email CASE WHEN HAS_ROLE('ADMIN')
      THEN email ELSE MASK_EMAIL(email) END;
      复制

      关于脱敏用法的详细介绍,见脱敏函数

    3. 查看授权设置,示例如下。

      > SHOW PERMISSION ON bank_account;
      +---------------+--------------------------------------------------------------------+
      |  row/column   |                             definition                             |
      +---------------+--------------------------------------------------------------------+
      | COLUMN name   | CASE WHEN HAS_ROLE('ADMIN') THEN name ELSE MASK(name, 1) END       |
      | COLUMN id     | CASE WHEN HAS_ROLE('ADMIN') THEN id ELSE MASK(id, 3, 4) END        |
      | COLUMN email  | CASE WHEN HAS_ROLE('ADMIN') THEN email ELSE MASK_EMAIL(email) END  |
      +---------------+--------------------------------------------------------------------+
      复制
    4. (可选)验证用户权限。

  • 以管理员 hive 身份连接数据库,可查看到完整的数据。

    > SET ROLE ADMIN;
    No rows affected (0.031 seconds)
    > SELECT * FROM bank_account;
    +--------+---------------------+------------------+
    |  name  |         id          |      email       |
    +--------+---------------------+------------------+
    | jack   | 511702198907108849  | jack@126.com     |
    | alice  | 530724198511061294  | alice@gmail.com  |
    | tom    | 320702199203128764  | tom@outlook.com  |
    | amy    | 440183198811183889  | amy@qq.com       |
    +--------+---------------------+------------------+
    复制
  • 以普通用户 normal_user 身份连接数据库,只能查看到脱敏后的数据。

    > SELECT * FROM bank_account;
    +--------+---------------------+------------------+
    |  name  |         id          |      email       |
    +--------+---------------------+------------------+
    | j***   | 511***********8849  | j***@126.com     |
    | a****  | 530***********1294  | a****@gmail.com  |
    | t**    | 320***********8764  | t**@outlook.com  |
    | a**    | 440***********3889  | a**@qq.com       |
    +--------+---------------------+------------------+
    复制
撤销列级权限设置
撤销指定列的权限设置

语法

REVOKE PERMISSION ON [TABLE] <table_name> FOR COLUMN <column_name>;
复制

示例

撤销 bank_account 表中,对 email 列的权限设置。

REVOKE PERMISSION ON bank_account FOR COLUMN email;
复制
撤销表中所有列的权限设置

语法

REVOKE PERMISSION ON [TABLE] <table_name> FOR COLUMNS;
复制

示例

撤销 bank_account 表中,对所有列的权限设置。

REVOKE PERMISSION ON bank_account FOR COLUMNS;
复制
查看行/列级权限

语法

SHOW PERMISSION ON TABLE <table_name>;
复制

如需查看表权限,可通过 SHOW GRANT 命令。

示例

> SHOW PERMISSION ON TABLE bank_account;
+---------------+--------------------------------------------------------------------+
|  row/column   |                             definition                             |
+---------------+--------------------------------------------------------------------+
| COLUMN name   | CASE WHEN HAS_ROLE('ADMIN') THEN name ELSE MASK(name, 1) END       |
| COLUMN id     | CASE WHEN HAS_ROLE('ADMIN') THEN id ELSE MASK(id, 3, 4) END        |
| COLUMN email  | CASE WHEN HAS_ROLE('ADMIN') THEN email ELSE MASK_EMAIL(email) END  |
+---------------+--------------------------------------------------------------------+
复制