因为行级安全性对于表的所有者以及超级用户等无效,因此原来的开发模型就不再适用,应用就需要通过单独的账户进行登录,这样就形成了三级账户体系:
超级用户(postgres):作为数据库系统的管理者,拥有整个数据库系统的所有权限;
数据库所有者:该账户作为数据库的管理者,拥有整个数据库的所有权限;
应用所有者:该账户默认只具有登录数据库的权限,其他的操作都需要相关授权;
应用通过应用所有者账户连接数据库,比如要对某个数据库的public模式内的所有表进行增删改查操作,则需要进行如下的授权:
假定登录用户为u1_public:
GRANT ALL ON ALL TABLES IN SCHEMA public TO u1_public;其他对象的权限授权也同理。
2.2.策略函数不管是USING表达式还是WITH CHECK表达式,都要求表达式的返回值是布尔值,但是对于表达式本身没有限制,因此对于一些复杂的场景,是可以写策略函数的,比如:
ALTER POLICY user_policy ON user USING(p());这个是合法的,只要p函数的返回值是布尔就可以。
这个p函数内部显然可以写复杂的逻辑,但是这个p函数暂时看不能传递参数,而且该函数只能返回布尔值也对该函数的发挥空间有了限制,不如Oracle的策略函数返回值是一个字符串的WHERE子句灵活,因为无法用于一些动态场景中。
2.3.动态参数最后一个问题,就是动态参数,就是具体的策略表达式或者策略函数依赖于应用操作者本身的一些具体的、事务级的参数,比如用户的id,用户所属的组织机构id等,甚至一些用户在界面上进行选择或者输入的数据。这个问题在Oracle中是通过数据库的上下文对象实现的,而在PostgreSQL中没有这样的对象。那么怎么办呢?
PostgreSQL的强大之处就在这里!这里我们要引入两个概念,一个是定制选项,一个是系统管理函数中的配置设定函数。
1.定制选项:
任何数据库,也包括其他的很多复杂软件,都有很多的配置参数,PostgreSQL也一样。在PostgreSQL中,有很多的内置参数,定义在postgresql.conf 中。
我们知道,PostgreSQL支持扩展,这些扩展可能也需要一些参数,那么在PostgreSQL中如何定义这些参数呢?他是通过定制选项提供这个功能。
定制选项由两部分组成,首先是扩展名,然后是一个.,然后是属性名,比如rls.userid。因为定制选项可能在扩展还没有加载之前就需要进行设定,因此PostgreSQL允许这些变量以占位符的形式存在直到扩展模块加载之前都不起任何作用,当扩展模块加载后才会赋予这些变量实际的含义。
了解了这一点,我们发现可以利用这个特性来进行动态参数的传递。
另外要提示一点,在PostgreSQL9.2版本之前,这个定制选项中的扩展名需要在postgres.conf文件中进行定义,比如custom_variable_classes=rls,而在9.2版本中取消了这一限制,这就给我们提供了更大的方便。
2.配置设定函数:
知道了PostgreSQL支持动态参数而且知道了动态参数的定义规则之后,下一步就需要知道如何对这些参数进行事务级的赋值/取值了,这时我们就需要利用配置设定函数了。
PostgreSQL中对于参数的设定,提供了三种方式,一个是SET命令,一个是对于内置参数的ALTER SYSTEM命令,再一个就是配置设定函数current_setting和set_config,而这两个函数正是我们需要的,我们看下这两个函数的定义:
名称
返回值
描述
current_setting(setting_name)
text
获取设定的当前值
set_config(setting_name,new_value,is_local)
text
设置参数然后返回新值
这里需要特别关注的就是set_config函数的第三个参数is_local,如果该参数为true,那么该参数只在当前事务有效,如果为false,则对当前会话有效。在SET命令中,也有和这个相对应的LOCAL/SESSION参数。
了解了这两个特性之后,我们就有了对应的应用层解决方案,需要两个步骤:
定义并传递参数:
可以在事务开启之后,进行相应的SQL操作之前进行,比如调用如下的SQL:
SELECT set_config('rls.userid', 'xiaoming', true);策略表达式或者策略函数中获取参数: