聊个前端很少接触的概念:行级安全策略

62dba732dd975e1bd428bb0e8d887e4a.png

作为前端工程师,行级安全策略(RLS)这个概念可能大家会有点陌生,不过没关系,一般情况下,大家估计也用不到。但是,如果你要开始思考开发一款完整的应用。了解他就显得很有必要了。


如果我们想要快速开发一个个人产品,但是又不想花太多的精力去配置数据库、管理身份校验、维护后端服务等等,那么 BaaS 平台就是非常适合我们的选择之一。

BaaS,Backend as a Service,后端及服务。

Supabase 是比较火的 BaaS 平台之一。在使用 Supabase 的过程中,我们可以为创建的数据表设置对应的行级安全策略,用于约束不同的访问规则。

RLS

行级安全,Row Level Security。作为项目管理员,我们可以单独为数据表创建访问策略。当接口访问数据库时,需要先确保这些策略验证通过之后,才能正常访问

3a9fbd5b7f6ed4cefc2317d2809170b4.png

如上图所示,Supabase 中,在创建好的数据表头部有一个按钮 Add RSL policy,点击该按钮,我们就可以添加对应的行级安全策略

6b73f2246016f5d2e71d4cd00b1faa67.png

然后点击 Create Policy,会出现如下创建页面。

e51fdf1bbee6ea8515daa22c4b15a5ca.png

在创建页面的右侧,有已经配置好的一些模板,如果对语法不熟悉,可以通过参考模板,并结合自己的需求来调整安全策略。

例如,针对用户表 users,我们可以约定一条规则,仅允许用户自己修改自己的那一条用户数据。配置的策略如下所示

create policy "Users can update their own profiles."
on users 
for update 
using (
  auth.uid() = id
);

1、create policy: Users... 第一行,是一句备注说明:用户可以修改自己的个人信息。

2、on users: users 是数据表的名称,表示该策略将会用于名为 users 的数据表。

3、for update: 表示该策略仅针对于更新操作生效

4、using: 表示一个业务级别的判断条件,例如这里的判断条件是 auth.uid() = id,表示当前的访问用户的 uid 需要与表中字段 id 的值相等,才能符合安全策略。

Policy Behavior

操作一个表有几种行为:SELECTINSERTUPDATEDELETEALL

我们可以针对同一个表、同一个表的同一个行为配置多个安全策略。那么接下来要思考的一个问题就是,多个安全策略我们需要同时都验证通过才能操作数据呢,还是只满足一个安全策略就可以了?

7c57dbbe9b8204b69e162528dc32f706.png

Supabase 提供了一个配置,让我们可以设置具体选择哪一种。其中有两个值

// OR
as PERMISSIVE
// AND
as RESTRICTIVE

Roles

Supabase 通过提供了一组预定义角色来增强安全策略的访问控制。在配置代码中,可以通过 to authenticated 来配置

create policy "Enable insert for authenticated users only"
on "public"."vip"
as PERMISSIVE
for INSERT
+ to authenticated
with check (
  true
);

有如下预定义角色

postgres: 具有完全权限的默认管理员角色

anon: 匿名用户,没有用户登录时访问数据库

authenticator: 这是一个特殊角色,访问权限非常优先。他基于 token 验证 JTWs 并解析出另外一个角色,例如,下面的对象是 JTWs 解码之后的结果,此时包含的角色为 anon

{
  "role": "anon",
  "iss": "supabase",
  "iat": 1614205174,
  "exp": 1929781174
}

authenticated: 表示 API 请求中,已经登录的用户

service_role: 绕过行级安全性来提升 API 访问权限。

supabase_auth_admin: 在迁移期间管理身份验证模式。访问范围仅限于 auth 架构。

supabase_storage_admin: 在迁移期间管理存储模式。访问范围仅限于 storage 架构。

dashboard_user: 通过 Supabase UI 执行命令。

supabase_admin: 数据库维护的管理角色。

除此之外,我们还可以通过 SQL 命令直接在 PostgreSQL 中创建新的角色

create role "new_role";

并且授予该角色特定的权限

grant select on table example_table to new_role;
a1f526e6d51502e8dd6f04cf9a63e6e6.png

运行成功之后,在安全策略的配置中,就可以选择刚才创建好的角色。

c739269eeb119b99f219af8042a9a688.png

using | with check

有的时候,我们会看到模板里面会出现 with check 语法。如下所示。

create policy "Enable update for users based on email"
on "public"."vip"
as PERMISSIVE
for UPDATE
to public
using (
  (select auth.jwt()) ->> 'email' = email
with check (
  (select auth.jwt()) ->> 'email' = email
);

这里的他的作用与 using 是类似的,都是表示执行一个判断条件。不过他们针对的数据不一样。using 针对数据表中已经存在的数据。而 with check 则针对新加入到数据表中的数据。

因此,with check 通常用于 INSERT、UPDATE 这样的可能会存在新加入数据表数据的行为中。

性能优化

行级安全策略虽然能够更大程度上保护数据的可见性,但是在执行的过程中,如果处理不当,依然有可能会造成不小的性能问题,导致数据访问速度过慢。因此,在编写安全策略的过程中,我们需要考虑如何以最小的成本来优化执行过程。

例如下面这个案例

create policy "rls_test_select" 
on test_table
to authenticated
using ( auth.uid() = user_id );

这里在执行 using 判断时,我们使用了 auth.uid() 方法,一个比较好的方式,就是多次访问时,我们可以缓存他的结果,从而加快后续的比较速度

我们可以稍微调整就可以做到想要的效果

create policy "rls_test_select" 
on test_table
to authenticated
using ( (select auth.uid()) = user_id );

只需要在 auth.uid() 前面添加上 select 即可。auth.jwt() 也可以用这种方式来优化。

另外一个优化策略,则是使用 B-TREE 建立索引的方式来加快查找速度。

create policy "rls_test_select" 
on test_table
to authenticated
using ( (select auth.uid()) = user_id );

添加 B-TREE 索引

create index userid
on test_table
using btree (user_id);

优化之后的速度会得到显著的提升

701db29e2c23ccede34c6b54df42367e.png

总结

针对数据库设计合理的行级安全策略,是管理数据安全的一种必备的手段。只是可能我们前端很少会接触到这些东西,所以整个内容会比较陌生。但是如果我们对 sql 语句有所学习的话,那么这些内容就非常的基础。作为前端开发在适当的时候也应该了解一些

- END -

如果您关注前端+AI 相关领域可以扫码进群交流

 da74e8a7050ca31d1dce4065f26ab555.jpeg

添加小编微信进群😊

关于奇舞团

奇舞团是 360 集团最大的大前端团队,非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

102bd6d2cb280b5480c9bce67ba3fb69.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值