前面讲过PostgreSQL RLS介绍,在使用MemFire Cloud的BaaS服务进行应用开发时,比较困扰开发者的是RLS的使用。本篇从基本的RLS使用以及基本示例入手,让用户理解如何使用RLS。
全称:Row level security,行级安全,允许系统管理员为数据库表创建访问策略(policy),以约束数据的可见性。创建策略语法详见:语法说明。当为一个表创建了policy后,相当于为该表增加了一个高优先级的过滤器。当用户访问该表时,如果policy生效,则会根据policy中定义的过滤条件来决定用户可操作的数据集合。
我们使用MemFire Cloud开发应用时,需要关注的对象包括数据表、云存储的bucket,可以使用RLS来设置用户的访问权限,保证用户数据安全性。
数据表里的RLS默认是不开启的,此时注册应用的用户是可以增删改查数据表中任何数据。
当用户开启了RLS,但没有设置任何访问策略时,会拒绝用户访问该表中的任何数据。
「补充说明」:如果启用RLS,至少要创建一条最简单的策略(如:允许任何人访问数据),否则接口调试时会查询不到数据。
以下是给指定表启用RLS的三种方法:
① 使用SQL命令启用RLS
RLS默认是不开启的,可针对每个表执行如下语句来对该表开启RLS功能:
ALTER TABLE ENABLE ROW LEVEL SECURITY
② 新建表时默认启用行级安全策略
③ 用户认证->策略->给指定表启用RLS
云存储bucket的RLS默认就是开启的,无需手动开启。新建bucket时,如果选择公开bucket,则任何人可以访问bucket中的对象文件;否则无权访问。
创建一个应用后,MemFire Cloud后台会默认创建一个auth.users系统表,主要用来记录用户的注册信息,其中有三个字段:id(用户唯一标识UID)、email(用户注册邮箱)、role(用户角色信息)。
应用开发者在创建数据表时,可使用一个字段来标记是哪个用户的数据,通常采用id(用户唯一标识UID)、email(用户注册邮箱)来标记。
MemFire Cloud封装了三个授权对象,用于获取向数据库发出请求的不同唯一标识,其中包括:
① 「角色」: 若想要根据用户的角色限制或允许访问某些表或行,则可以使用to,to用于获取向数据库发出请求的用户的当前角色。to后面可以跟着下列之一:已认证的(authenticated),匿名的(anon),或你定义的自定义角色。
例如:仅允许身份验证用户启用访问权限
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
to authenticated
using (
true
);
② 「邮箱」:若想要根据用户的电子邮件限制或允许访问某些表或行,则可以使用auth.jwt() ->> ‘email’,它用于获取向数据库提出请求的用户的email。
例如:根据电子邮件为用户启用权限
假定您的表有一个“email”列,并允许用户操作“email”列与其电子邮件匹配的行
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
USING( auth.jwt() ->> 'email' = 'email' ) ;
③ 「用户id」:若想要根据用户的id限制或允许访问某些表或行,则可以使用auth.uid(),它用于获取向数据库提出请求的用户的唯一标识符(UID)。
例如:根据用户ID为用户启用访问权限
假定您的表有一个“user_id”列,并允许用户操作“user_id”列与其ID 匹配的行
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
USING( auth.uid() = "user_id" ) ;
为所有用户提供对数据表的访问权限
「当USING设置为true时,表示访问数据表时不需要做任何校验」
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
USING( true ) ;
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
to authenticated
using (
true
);
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
USING( auth.jwt() ->> 'email' = 'email' ) ;
Create POLICY "策略名称"
ON public."表名"
AS PERMISSIVE
FOR SELECT
USING( auth.uid() = "user_id" ) ;
① 指定路径的文件,例如:
name='admin/assets/example.png'
② 获取文件的指定层级文件夹名称,例如:
(storage.foldername(name))[1]='admin'
③ 发起请求用户的角色,这里的角色可以是已认证的(authenticated),匿名的(anon),或你定义的自定义角色,例如:
to authenticated
④ 发起请求的用户uid等于文件夹名称,例如:
auth.uid()::text=(storage.foldername(name))[1]
⑤获取文件的扩展名,例如:
storage."extension"(name)='jpg'
⑥ 发起请求的用户uid等于指定值,例如:
auth.uid()::text='abcd'
CREATE POLICY "策略名称"
ON storage.objects
--- 指定操作类型
FOR SELECT
-- 对匿名用户
TO anon
---使用USING 或 WITH CHECK 来检查
{USING | WITH CHECK} (
bucket_id = '存储桶名称'
-- 只允许访问JPG文件
AND storage."extension"(name) = 'jpg'
-- 在public文件夹下
AND LOWER((storage.foldername(name))[1]) = 'public'
);
CREATE POLICY "策略名称"
ON storage.objects
--- 指定操作类型
FOR SELECT
---使用USING 或 WITH CHECK 来检查
{USING | WITH CHECK} (
bucket_id = '存储桶名称'
---发起请求的用户uid等于文件夹名称
AND auth.uid()::text = (storage.foldername(name))[1]
);
CREATE POLICY "策略名称"
ON storage.objects
--- 指定操作类型
FOR SELECT
-- 仅允许身份验证访问
to authenticated
---使用USING 或 WITH CHECK 来检查
{USING | WITH CHECK} (
AND (storage.foldername(name))[1] = 'private'
);
CREATE POLICY "策略名称"
ON storage.objects
--- 指定操作类型
OR SELECT
---使用USING 或 WITH CHECK 来检查
{USING | WITH CHECK} (
bucket_id = '存储桶名称'
---获取文件的指定层级文件夹名称
AND (storage.foldername(name))[1] = 'admin'
AND (storage.foldername(name))[2] = 'assets'
---指定特定用户才能访问
AND auth.uid()::text = 'd7bed83c-44a0-4a4f-925f-efc384ea1e50'
);
CREATE POLICY "策略名称"
ON storage.objects
--- 指定操作类型
FOR SELECT
---使用USING 或 WITH CHECK 来检查
{USING | WITH CHECK} (
bucket_id = '存储桶名称'
---指定路径的文件
AND name = 'admin/assets/Costa Rican Frog.jpg'
---指定特定用户才能访问
AND auth.uid()::text = 'd7bed83c-44a0-4a4f-925f-efc384ea1e50'
);
CREATE POLICY name ON table_name
[ AS { PERMISSIVE | RESTRICTIVE } ]
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
[ TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( using_expression ) ]
[ WITH CHECK ( check_expression ) ]