为 SSR 创建 Supabase 客户端
Configure your Supabase client to use cookies
要在 Supabase 中使用服务端渲染(SSR),你需要配置 Supabase 客户端使用 cookies。@supabase/ssr 包可以帮你在 JavaScript/TypeScript 应用中做到这一点。
🌐 To use Server-Side Rendering (SSR) with Supabase, you need to configure your Supabase client to use cookies. The @supabase/ssr package helps you do this for JavaScript/TypeScript applications.
安装 #
🌐 Install
安装 @supabase/supabase-js 和 @supabase/ssr 辅助包:
🌐 Install the @supabase/supabase-js and @supabase/ssr helper packages:
1npm install @supabase/supabase-js @supabase/ssr设置环境变量 #
🌐 Set environment variables
在项目根目录下创建一个 .env.local 文件。在文件中,设置项目的 Supabase URL 和 Key:
🌐 Create a .env.local file in the project root directory. In the file, set the project's Supabase URL and Key:
获取 API 详情 #
🌐 Get API details
要与数据库表中的数据进行交互,你可以使用封装了自动生成的数据 API 端点的客户端库,并使用来自项目 Connect 对话框的项目 URL 和密钥进行认证。
🌐 To interact with data in database tables, you use the client libraries that wrap the auto-generated Data API endpoints, authenticating using the Project URL and key from the project Connect dialog.
阅读 API 密钥文档 以全面了解所有密钥类型、用途以及在哪里可以找到它们。
1NEXT_PUBLIC_SUPABASE_URL=supabase_project_url2NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=supabase_publishable_key创建一个客户 #
🌐 Create a client
你需要一些设置代码来配置 Supabase 客户端以使用 Cookie。一旦你有了这些工具代码,你就可以使用 createClient 工具函数来获取一个配置好的 Supabase 客户端。
🌐 You need setup code to configure a Supabase client to use cookies. Once you have the utility code, you can use the createClient utility functions to get a properly configured Supabase client.
在浏览器上运行的代码里用浏览器客户端,在服务器上运行的代码里用服务器客户端。
🌐 Use the browser client in code that runs on the browser, and the server client in code that runs on the server.
Supabase Auth SDK 包含三种不同的函数,用于验证用户对应用的访问权限:
🌐 The Supabase Auth SDK contains three different functions for authenticating user access to applications:
方法总结 #
🌐 Summary of the methods
- 使用
getClaims来保护页面和用户数据。它会从存储中读取访问令牌并进行验证。在本地通过 WebCrypto API 和缓存的 JWKS 端点进行操作,当项目使用非对称签名密钥时(这是新项目的默认设置);如果使用对称密钥,则仅通过调用getUser来验证。返回的声明总是来自解析 JWT,而不是通过用户查询获得。 [getUser](/docs/reference/javascript/auth-getuser)会向项目的 Auth 实例发起网络请求以获取用户记录,这样可以获得用户的最新信息,但需要进行一次网络请求。getSession当你需要原始会话(访问令牌、刷新令牌和过期时间)时使用。例如,将访问令牌转发到另一个服务。会话是直接从本地存储加载的,并不会重新向认证服务器验证,因此当存储与客户端共享(如 cookies、请求头)时,嵌入的用户对象不应单独信任。要验证身份,请使用getClaims验证访问令牌,或调用getUser获取一个新的、服务器确认的用户记录。
总结:使用 getClaims 来验证身份(通常用于保护页面和数据),当你需要从认证服务器获取最新的用户记录时用 getUser,而当你直接需要访问或刷新令牌时用 getSession,但不要依赖它返回的用户对象来做授权决策。
编写实用函数来创建 Supabase 客户端 #
🌐 Write utility functions to create Supabase clients
要从 Next.js 应用访问 Supabase,你需要两种类型的 Supabase 客户端:
🌐 To access Supabase from a Next.js app, you need 2 types of Supabase clients:
- 客户端组件 client - 用于从在浏览器中运行的客户端组件访问 Supabase。
- 服务器组件客户端 - 用于从仅在服务器上运行的服务器组件、服务器操作和路由处理程序中访问 Supabase。
由于 Next.js 服务器组件不能写入 cookie,你需要一个 代理 来刷新过期的认证令牌并存储它们。
🌐 Since Next.js Server Components can't write cookies, you need a Proxy to refresh expired Auth tokens and store them.
代理负责:
🌐 The Proxy is responsible for:
- 通过调用
supabase.auth.getClaims()刷新认证令牌。 - 将刷新后的认证令牌传递给服务器组件,这样它们就不会自己尝试刷新同一个令牌。这可以通过
request.cookies.set来实现。 - 将更新后的认证令牌传递给浏览器,以替换旧的令牌。这是用
response.cookies.set完成的。
Supabase Auth SDK 包含三种不同的函数,用于验证用户对应用的访问权限:
🌐 The Supabase Auth SDK contains three different functions for authenticating user access to applications:
方法总结 #
🌐 Summary of the methods
- 使用
getClaims来保护页面和用户数据。它会从存储中读取访问令牌并进行验证。在本地通过 WebCrypto API 和缓存的 JWKS 端点进行操作,当项目使用非对称签名密钥时(这是新项目的默认设置);如果使用对称密钥,则仅通过调用getUser来验证。返回的声明总是来自解析 JWT,而不是通过用户查询获得。 [getUser](/docs/reference/javascript/auth-getuser)会向项目的 Auth 实例发起网络请求以获取用户记录,这样可以获得用户的最新信息,但需要进行一次网络请求。getSession当你需要原始会话(访问令牌、刷新令牌和过期时间)时使用。例如,将访问令牌转发到另一个服务。会话是直接从本地存储加载的,并不会重新向认证服务器验证,因此当存储与客户端共享(如 cookies、请求头)时,嵌入的用户对象不应单独信任。要验证身份,请使用getClaims验证访问令牌,或调用getUser获取一个新的、服务器确认的用户记录。
总结:使用 getClaims 来验证身份(通常用于保护页面和数据),当你需要从认证服务器获取最新的用户记录时用 getUser,而当你直接需要访问或刷新令牌时用 getSession,但不要依赖它返回的用户对象来做授权决策。
在你的项目根目录下创建一个 lib/supabase 文件夹,或者如果你正在使用 ./src 文件夹,就在里面创建,每种客户端类型都放一个文件。然后复制每种客户端类型的 lib 工具函数。
🌐 Create a lib/supabase folder at the root of your project, or inside the ./src folder if you are using one, with a file for each type of client. Then copy the lib utility functions for each client type.
1import { createBrowserClient } from '@supabase/ssr'23export function createClient() {4 return createBrowserClient(5 process.env.NEXT_PUBLIC_SUPABASE_URL!,6 process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!7 )8}连接代理 #
🌐 Hook up proxy
这段代码添加了一个 matcher,这样 Proxy 就不会在不访问 Supabase 的路由上运行。
🌐 The code adds a matcher so the Proxy doesn't run on routes that don't access Supabase.
在保护页面时要小心。服务器是从 cookies 获取用户会话的,这可能被任何人伪造。
🌐 Be careful when protecting pages. The server gets the user session from the cookies, which can be spoofed by anyone.
总是使用 supabase.auth.getClaims() 来保护页面和用户数据。
🌐 Always use supabase.auth.getClaims() to protect pages and user data.
在服务器代码里,比如代理,_绝对不要_信任 supabase.auth.getSession()。它不能保证重新验证 Auth 令牌。
🌐 Never trust supabase.auth.getSession() inside server code such as Proxy. It isn't guaranteed to revalidate the Auth token.
相信 getClaims() 是安全的,因为它每次都会用项目公布的公钥验证 JWT 签名。
🌐 It's safe to trust getClaims() because it validates the JWT signature against the project's published public keys every time.
Supabase Auth SDK 包含三种不同的函数,用于验证用户对应用的访问权限:
🌐 The Supabase Auth SDK contains three different functions for authenticating user access to applications:
方法总结 #
🌐 Summary of the methods
- 使用
getClaims来保护页面和用户数据。它会从存储中读取访问令牌并进行验证。在本地通过 WebCrypto API 和缓存的 JWKS 端点进行操作,当项目使用非对称签名密钥时(这是新项目的默认设置);如果使用对称密钥,则仅通过调用getUser来验证。返回的声明总是来自解析 JWT,而不是通过用户查询获得。 [getUser](/docs/reference/javascript/auth-getuser)会向项目的 Auth 实例发起网络请求以获取用户记录,这样可以获得用户的最新信息,但需要进行一次网络请求。getSession当你需要原始会话(访问令牌、刷新令牌和过期时间)时使用。例如,将访问令牌转发到另一个服务。会话是直接从本地存储加载的,并不会重新向认证服务器验证,因此当存储与客户端共享(如 cookies、请求头)时,嵌入的用户对象不应单独信任。要验证身份,请使用getClaims验证访问令牌,或调用getUser获取一个新的、服务器确认的用户记录。
总结:使用 getClaims 来验证身份(通常用于保护页面和数据),当你需要从认证服务器获取最新的用户记录时用 getUser,而当你直接需要访问或刷新令牌时用 getSession,但不要依赖它返回的用户对象来做授权决策。
1import { type NextRequest } from 'next/server'2import { updateSession } from '@/lib/supabase/proxy'34export async function proxy(request: NextRequest) {5 return await updateSession(request)6}78export const config = {9 matcher: [10 /*11 * Match all request paths except for the ones starting with:12 * - _next/static (static files)13 * - _next/image (image optimization files)14 * - favicon.ico (favicon file)15 * Feel free to modify this pattern to include more paths.16 */17 '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',18 ],19}恭喜 #
🌐 Congratulations
你完成了!回顾一下,你已经成功地:
🌐 You're done! To recap, you've successfully:
- 从服务器操作中调用了 Supabase。
- 从服务器组件调用了 Supabase。
- 设置一个 Supabase 客户端工具,以便从客户端组件调用 Supabase。如果你需要从客户端组件调用 Supabase,比如设置实时订阅,就可以使用它。
- 设置代理以自动刷新 Supabase Auth 会话。
你现在可以在客户端或服务器端代码中使用任何 Supabase 功能了!
🌐 You can now use any Supabase features from your client or server code!
缓存注意事项 #
🌐 Caching considerations
如果你的应用使用 ISR(增量静态再生成)或者部署在 CDN 后面,HTTP 响应的缓存可能会导致用户收到别人的会话。当会话被刷新时,新令牌会通过 Set-Cookie 写入响应。如果该响应被缓存并提供给其他用户,那么这个用户就会以错误的身份登录。
🌐 If your app uses ISR (Incremental Static Regeneration) or is deployed behind a CDN, caching of HTTP responses can cause users to receive another user's session. When a session is refreshed, the new token is written to the response via Set-Cookie. If that response is cached and served to a different user, that user will be signed in as the wrong person.
详细信息和特定框架的示例,请参阅 高级 Auth 服务器端渲染指南。
🌐 See the advanced Auth server-side rendering guide for details and framework-specific examples.
下一步 #
🌐 Next steps