【原理篇】Supabase的API Key工作机制和使用场景

Supabase的API Key

跟大多数公网服务一样,Supabase通过API Key来约束客户端对REST API的访问。有所不同的是,大多数公网服务的API Key都是需要用户保密的,一旦泄露,会导致恶意用户直接操作所使用的服务接口,典型的例子如:ChatGPT。因此一般公网服务的API key只能在服务端使用。

Supabase的服务形式有所不同,他允许开发者直接在web或app客户端调用接口,大家都知道,API key配置在客户端上是没有保密性的,尤其JavaScript明文直接就可以被任何人看到,因此Supabase内置了两个API Key,以应对该问题:

  • Anon Key

这个API Key是可以在Web和移动应用客户端使用的key,不需要担心key泄露。顾名思义,这个key默认对应的是一个anon(匿名)用户,匿名用户具有最低的数据访问权,通常不能访问任何数据,因此不必担心key泄露后的安全问题。那么问题来了,一个最低权限的API key如何给开发者使用来开发应用呢?我会在下文介绍其工作原理。

  • Service Role Key

这个Key具有最高的API访问权限,用户使用该Key可以进行任意操作,因此只能配置到服务端使用,不能泄露。所以Service Role Key扮演的是大家常见的API Key的角色。

简单来说,Supabase提供了2个Key,如果是Web或者移动应用,直接在客户端调用Supabase接口的话,必须使用Anon key。服务端程序则可以根据场景需要来决定使用Anon key还是Service Role Key。具体使用方法我们在下文详细介绍。

API Key的验证流程

在介绍验证流程前,我们看一下使用API Key调用Supabase接口的方法:

curl 'https://xxx.com/rest/v1/mytable?select=id' \
-H "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImV4cCI6MzIxODIzMDc4NSwiaWF0IjoxNjgwMzEwNzg1LCJpc3MiOiJzdXBhYmFzZSJ9.asHw-mbtQPRj9GZW0Ab1bfNXQU5_X7g01lX8mrcMxFs" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImV4cCI6MzIxODIzMDc4NSwiaWF0IjoxNjgwMzEwNzg1LCJpc3MiOiJzdXBhYmFzZSJ9.asHw-mbtQPRj9GZW0Ab1bfNXQU5_X7g01lX8mrcMxFs"

可以看到上面HTTP请求指定了两个Header:

  • apikey:调用Supabase接口所需要的API Key

  • Authorization:当前会话的用户认证token

下图是Supabase的验证API Key的一般过程:

【原理篇】Supabase的API Key工作机制和使用场景_第1张图片

  1. 客户端携带Anon key和Anon Token,调用Login接口

  2. kong接收到API调用请求后,验证apikey是否符合要求,这里必须二选一,要么是anon key,要么是service role key。验证失败,则直接返回客户端key错误。验证通过则将登录请求转发给Auth服务。

  3. Auth处理登录请求,并返回登录成功后的用户认证token。

  4. kong将登录请求的最终结果返回给客户端,此时如果登录成功,客户端会拿到正式的认证token。

  5. 登录成功后,客户端调用REST接口访问数据,此时apikey仍旧传anon key,而Authorization Token则需要填Auth服务返回的Token。

  6. kong仍旧只验证apikey,发现是anon或者service role key则将请求转发给postgrest服务。

  7. postgrest解析Authorization Token,并识别相应的角色和用户信息,根据权限设置来判断当前登录的用户是否有对应用户的数据访问权限,有则继续执行具体的操作,没有则报错。操作执行完后,返回用户需要的数据。

  8. kong将最终结果返回给客户端。

以上是一轮常规API请求的执行流程,当然,用户登录只需要执行一次,直到Authorization Token过期,都不需要再次登录。

我们回头看一下上面API调用示例中curl命令传递的两个参数,会发现apikey和Authorization传的都是Anon Key。如果此时不调用登录接口,直接调用REST API操作数据,会发生什么事情呢?我们沿着API调用路径来看一下执行流程:

  • 首先,kong会校验apikey认为该API调用是合法的,将请求转发给postgrest服务。

  • postgrest服务解析Authorization Token,发现解析出来的role是anon,此时该api是否能正常执行,取决于anon role是否有相应的权限。为什么postgrest会解析role,以及如何解析role的,请参考《SupaBase权限模型part2》

  • 如果用户关闭了RLS,是不会校验任何权限的,此时接口会正常执行。

  • 如果用户开启了RLS,默认anon用户没有任何数据的访问权限,以该接口为例(查询mytable表的id字段),会返回空列表。

  • 如果开发者期望anon用户也能读取某些数据,就需要为anon设置相应的权限。比较典型的场景,比如微博,用户没有登录也是可以看到其他用户发的微博信息的,这类场景就需要为anon用户开启数据访问权。

如果用户传给apikey和Authorization的是service role key,又会发生什么呢?

  • kong仍旧只校验apikey并放行

  • postgrest提取出来的role是service_role,该角色拥有最高权限,因此不论用户是否开启了RLS以及设置了何种规则,都会被无视。

  • service role拥有所有数据的访问权。

如何正确使用Anon key和ServiceRole key

可以参照如下一些基本原则:

  1. 客户端只能配置Anon key。需要配合RLS策略来管理数据访问权限。

  2. 服务端可以配置Anon key,也可以配置ServiceRole key。

  3. ServiceRole key会绕过所有RLS管控策略,因此使用ServiceRole key开发应用时,数据访问权限需要在程序中实现,不能依赖Supabase的RLS策略。

  4. 一些特定的API只能使用ServiceRole key访问,比如postgres-meta的API。

你可能感兴趣的:(serverless,postgresql,数据库)