高级指南
面向高级用户的SSR认证流程与实现细节
当用户通过 Supabase Auth 进行身份验证时,服务器会颁发两条信息:
- 访问令牌:以 JWT 形式存在
- 刷新令牌:随机生成的字符串
如果不使用 SSR(服务器端渲染),默认行为是将这些信息存储在本地存储(local storage)中。由于服务器无法访问本地存储,因此在 SSR 场景下,令牌需要存储在安全的 cookie 中。这样 cookie 就可以在客户端应用代码和服务器端应用代码之间来回传递。
如果不使用 SSR,您可能正在使用隐式流来获取访问令牌和刷新令牌。在该流程中服务器无法访问令牌,因此对于 SSR,您应该改用PKCE 流程。如果您的客户端库支持此选项,可以在初始化 Supabase 客户端时更改流程类型。
在 @supabase/ssr
包中,Supabase 客户端默认使用 PKCE 流程。它们还会自动配置为处理 cookie 中的会话信息保存和检索。
工作原理
在 PKCE 流程中,系统会重定向到您的应用,URL 中包含一个授权码。当您使用 exchangeCodeForSession
交换此代码时,会收到包含访问令牌和刷新令牌的会话信息。
为了维持会话,这些令牌必须安全地存储在客户端和服务器共享的存储介质中,传统上使用 cookie。每当会话刷新时,必须更新共享存储介质中的认证令牌和刷新令牌。Supabase 客户端库在初始化客户端时提供了可自定义的 storage
选项,允许您更改令牌的存储位置。
有关实现示例,请参阅 @supabase/ssr 包。
常见问题
Next.js路由预取时服务器端没有会话?
当您使用Next.js的<Link href="/...">
组件或Router.push()
API进行路由预取时,可能会在浏览器处理访问令牌和刷新令牌之前发送服务器端请求。这意味着这些请求可能没有设置任何cookie,导致您的服务器代码渲染未认证的内容。
为了改善用户体验,我们建议在用户登录后将其重定向到一个不包含Next.js路由预取的特定页面。一旦浏览器中运行的Supabase客户端库从URL片段获取了访问令牌和刷新令牌,您就可以将用户导航到使用预取功能的页面。
如何将cookie设置为HttpOnly
?
这没有必要。访问令牌和刷新令牌的设计初衷就是在应用程序的不同组件间传递。基于浏览器的应用程序需要访问刷新令牌来正确维护浏览器会话。
我的服务器收到无效刷新令牌错误,怎么回事?
很可能是从浏览器发送到服务器的刷新令牌已过期。请确保onAuthStateChange
监听器回调没有错误,并且在应用程序生命周期中注册得足够早。
当您在服务器端收到此错误时,可以尝试将渲染推迟到浏览器端,在那里客户端库可以访问最新的刷新令牌,为用户提供更好的体验。
是否应该为cookie设置较短的Max-Age
参数?
Max-Age
或Expires
cookie参数仅控制浏览器是否将值发送到服务器。由于刷新令牌代表用户在该浏览器上的长期认证会话,为cookie设置较短的Max-Age
或Expires
参数只会导致用户体验下降。
确保用户已注销或其会话已结束的唯一方法是使用getUser()
获取用户详细信息。
SameSite
属性应该使用什么值?
请确保您了解该属性在不同情况下的行为,因为某些属性可能会降低用户体验。
一个良好的默认值是使用Lax
,当用户导航到您的站点时会发送cookie。Cookie通常需要Secure
属性,这确保它们仅通过HTTPS发送。但在localhost
上开发时,这可能会造成问题。
是否可以将服务器端渲染与CDN或缓存一起使用?
可以,但需要注意至少将刷新令牌cookie值包含在缓存键中。否则您可能会意外地为不同用户提供包含错误数据的页面!
同时请确保设置适当的缓存控制头。我们建议每小时或更短时间内使缓存键失效。
哪些认证流程支持PKCE?
目前,PKCE支持在Magic Link、OAuth、注册和密码恢复路由上使用。这些对应于Supabase客户端库中的signInWithOtp
、signInWithOAuth
、signUp
和resetPasswordForEmail
方法。当在手机和邮箱OTP中使用PKCE时,与隐式流相比行为没有变化——请求成功时访问令牌仍会在响应体中返回。