写点什么

【原理篇】Supabase 应用开发为什么要配置 RLS

作者:张文平
  • 2024-01-03
    湖北
  • 本文字数:2017 字

    阅读完需:约 7 分钟

【原理篇】Supabase应用开发为什么要配置RLS

为什么需要 RLS

SupaBase 的接口使用比较灵活,可以在客户端直接调用,也可以在服务端调用。开发过 web 应用的同学在处理数据访问权限时应该比较熟悉一些基本的套路,甚至这些套路已经固化到了开发习惯中。我们以一个典型场景来说明一下传统 Web 开发过程中,数据鉴权的流程:



通常我们都会按照上面的思路来编写后端代码,校验用户是否有权限访问数据库中的某一条数据。同样的,在查询数据时,我们通常也是在后端程序中通过过滤条件来查询数据,以确保返回的数据是当前用户有权限访问的。


SupaBase 提供了灵活的数据库访问接口,让开发者可以在前端代码中直接访问数据库中的数据,那么开发者能采用相同的模式在前端通过代码来实现类似的数据权限访问控制吗?


答案是:不能。


原因很直观。代码运行在客户端和服务端的差异非常明显,服务端代码是受保护的,用户无法篡改服务端程序的代码,因此在服务端代码中进行数据权限访问控制是可靠的。但是客户端不同,用户如果有一定的编码能力,可以随意改动客户端代码,尤其是像 JavaScript 这种脚本语言,代码都是明文的,更加方便修改。所以在客户端编写权限访问控制的代码逻辑是不合适的。所有的权限控制必须在服务端实现。


SupaBase 解决这个问题的方案就是利用 Postgrest RLS 策略来实现数据访问控制,对于不熟悉 Postgrest 数据库的开发者,在阅读本篇内容之前,建议先阅读 【原理篇】SupaBase 权限模型part1

所有表都必须开启 RLS 吗

这是开发者比较关心的一个问题。简单回答:生产环境必须开 RLS。


如果不开启 RLS,数据库中的数据等于是对所有人开放的,任何人都可以通过接口对数据库中的所有数据进行增删查改操作,这显然不是开发者期望的结果。所以,使用 Supabase 开发应用时,只要上线就必须开启 RLS。

什么情况下可以对某个表不开启 RLS 呢?

你可能会说,如果该表中的数据是公开的,所有人都可以看的,不需要进行权限控制,这种表就可以不开启 RLS。但事实上,即使是开放数据,开发者也通常不希望数据被任意篡改,所以生产环境下,即使是公开的数据表,通常也需要开启 RLS,然后设置策略:运行任何人读取该表中的数据。

如何配合 RLS 编写客户端代码

文章开头我们提到,开发者习惯于在代码中编写权限控制代码,这种习惯无比强大,以致于即使开启了 RLS 并配置了相关策略,也还是会习惯性的在客户端代码中增加权限控制的逻辑。举一个例子:todos 表定义如下:


create table todos (    id serial primary key,    user_id uuid,    task text,    ......)
复制代码


用户 A 查询自己的 TODS 列表,开发者会不自然的写出如下代码:


const { data, error } = await supabase  .from('todos')  .select()  .eq('user_id', current_login_userid)
复制代码


上面代码中,开发者通过'user_id'字段来过滤出当前登录用户的数据,然后在显示到 UI 界面上。这样写虽然没有问题,但事实上是没有必要的。开发者仍旧寄希望通过前端代码来控制返回的数据范围。


正确的写法是:


const { data, error } = await supabase  .from('todos')  .select()
复制代码


同时,需要在数据库中配置如下策略


CREATE POLICY '用户只能访问自己的数据'  ON todos  USING (auth.uid() = user_id)  WITH CHECK (auth.uid() = user_id);
复制代码


我们不自然的会产生一个疑问,数据访问控制全部在服务端通过 RLS 策略完成,那么过滤条件有什么用呢?客户端还有必要写过滤条件吗?


回答是:有。在客户端进行数据过滤主要是为了更精准的展示用户想看的数据,而不是为了权限控制。很多时候,用户的数据量是非常多的,这时候,用户可能只想看自己数据的一部分子集,比如用户只想看自己近三年的数学成绩,这种情况就需要在客户端编写过滤逻辑,只查询需要的数据。


也有同学会说,我可以把所有数据全部查出来,然后用 js 在客户端进行过滤。技术上没有问题,但性能会差一些,每次查询客户端和服务端要进行大量的数据通信。

不会写 RLS 策略,能使用 SupaBase 开发应用吗

答案:能。


SupaBase 并没有限制用户的开发模式。SupaBase 允许开发者在客户端直接访问数据库,这是 SupaBase 的优势,但开发者仍旧可以在服务端使用 SupaBase 的 SDK 开发应用。


当我们在服务端使用 SupaBase 开发应用时,主场又回到了开发者这一侧。我们可以在服务端编写任意的逻辑代码,不用担心这些逻辑被篡改。因此在服务端使用 SupaBase 时,开发者可以跟传统开发模式一样,通过程序来控制数据访问权限,不再依赖 RLS 策略。


需要注意的是,不依赖 RLS 策略,也需要开启 RLS。原因前面解释过,如果不开启 RLS,数据库中的数据任何人都可以随意操作。


开启 RLS,但不配置任何策略,这样,客户端就没有任何权限操作数据库了。那服务端如何操作数据库呢?


这里就需要用到 service_role key 。我们在开发客户端程序时,配置的是 anon key 。anon key 是可以配置在客户端的,使用 anon key 访问数据库会收到 RLS 策略的限制,而 service_role key 不受 RLS 策略的约束,可以绕过 RLS 策略访问数据库中的任何数据。


所以,这里千万记住。service_role key 只能在服务端使用,不能泄露。

发布于: 刚刚阅读数: 5
用户头像

张文平

关注

Supabase先行者 2020-08-24 加入

还未添加个人简介

评论

发布
暂无评论
【原理篇】Supabase应用开发为什么要配置RLS_权限_张文平_InfoQ写作社区