认证

高级指南

面向高级用户的SSR认证流程与实现细节


当用户通过 Supabase Auth 进行身份验证时,服务器会颁发两条信息:

  1. 访问令牌:以 JWT 形式存在
  2. 刷新令牌:随机生成的字符串

如果不使用 SSR(服务器端渲染),默认行为是将这些信息存储在本地存储(local storage)中。由于服务器无法访问本地存储,因此在 SSR 场景下,令牌需要存储在安全的 cookie 中。这样 cookie 就可以在客户端应用代码和服务器端应用代码之间来回传递。

如果不使用 SSR,您可能正在使用隐式流来获取访问令牌和刷新令牌。在该流程中服务器无法访问令牌,因此对于 SSR,您应该改用PKCE 流程。如果您的客户端库支持此选项,可以在初始化 Supabase 客户端时更改流程类型。

工作原理

在 PKCE 流程中,系统会重定向到您的应用,URL 中包含一个授权码。当您使用 exchangeCodeForSession 交换此代码时,会收到包含访问令牌和刷新令牌的会话信息。

为了维持会话,这些令牌必须安全地存储在客户端和服务器共享的存储介质中,传统上使用 cookie。每当会话刷新时,必须更新共享存储介质中的认证令牌和刷新令牌。Supabase 客户端库在初始化客户端时提供了可自定义的 storage 选项,允许您更改令牌的存储位置。

有关实现示例,请参阅 @supabase/ssr 包。

常见问题

Next.js路由预取时服务器端没有会话?

当您使用Next.js的<Link href="/...">组件或Router.push()API进行路由预取时,可能会在浏览器处理访问令牌和刷新令牌之前发送服务器端请求。这意味着这些请求可能没有设置任何cookie,导致您的服务器代码渲染未认证的内容。

为了改善用户体验,我们建议在用户登录后将其重定向到一个不包含Next.js路由预取的特定页面。一旦浏览器中运行的Supabase客户端库从URL片段获取了访问令牌和刷新令牌,您就可以将用户导航到使用预取功能的页面。

这没有必要。访问令牌和刷新令牌的设计初衷就是在应用程序的不同组件间传递。基于浏览器的应用程序需要访问刷新令牌来正确维护浏览器会话。

我的服务器收到无效刷新令牌错误,怎么回事?

很可能是从浏览器发送到服务器的刷新令牌已过期。请确保onAuthStateChange监听器回调没有错误,并且在应用程序生命周期中注册得足够早。

当您在服务器端收到此错误时,可以尝试将渲染推迟到浏览器端,在那里客户端库可以访问最新的刷新令牌,为用户提供更好的体验。

Max-AgeExpirescookie参数仅控制浏览器是否将值发送到服务器。由于刷新令牌代表用户在该浏览器上的长期认证会话,为cookie设置较短的Max-AgeExpires参数只会导致用户体验下降。

确保用户已注销或其会话已结束的唯一方法是使用getUser()获取用户详细信息。

SameSite属性应该使用什么值?

请确保您了解该属性在不同情况下的行为,因为某些属性可能会降低用户体验。

一个良好的默认值是使用Lax,当用户导航到您的站点时会发送cookie。Cookie通常需要Secure属性,这确保它们仅通过HTTPS发送。但在localhost上开发时,这可能会造成问题。

是否可以将服务器端渲染与CDN或缓存一起使用?

可以,但需要注意至少将刷新令牌cookie值包含在缓存键中。否则您可能会意外地为不同用户提供包含错误数据的页面!

同时请确保设置适当的缓存控制头。我们建议每小时或更短时间内使缓存键失效。

哪些认证流程支持PKCE?

目前,PKCE支持在Magic Link、OAuth、注册和密码恢复路由上使用。这些对应于Supabase客户端库中的signInWithOtpsignInWithOAuthsignUpresetPasswordForEmail方法。当在手机和邮箱OTP中使用PKCE时,与隐式流相比行为没有变化——请求成功时访问令牌仍会在响应体中返回。