ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Redwood 集成 Supabase Auth 实战:配置、注册、登录、登出与认证状态导航完整指南

Redwood 集成 Supabase Auth 实战:配置、注册、登录、登出与认证状态导航完整指南 后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载本篇技术指南以 Redwood 项目中的官方实战手册docs/versioned_docs/version-6.x/how-to/supabase-auth.md为核心完整讲解如何将 Supabase 认证Auth接入 Redwood 应用从一条 CLI 命令完成配置、在管理控制台获取密钥到亲手实现注册Sign Up页、登录Sign In页、登出Sign Out按钮以及根据认证状态自动切换的导航链接。读完后你将掌握 Redwood Auth 抽象层与 Supabase GoTrueJS 客户端之间的协作关系并能独立为任意 Redwood 页面接入完整的邮箱密码认证闭环。为什么选择 Supabase Auth这篇 How-to 本质上可视为 Redwood 官方 GoTrue Auth 实战手册 的 Supabase 移植版。原因很简单Supabase 的认证服务建立在 Netlify GoTrue 这一开源基础之上——它是一个专门处理用户注册与认证的 API 服务。当你理顺这条技术脉络后GoTrue 系的实战手册就变成了攀登认证学习曲线的现成阶梯。对 Redwood 来说最终使用的是 Redwood Auth 包装层它提供了一层抽象与统一、简洁的 API 风格。不过先直接与 Supabase Client 打交道一两个小时例如跟随 Supabase 的 React Quick Start 走一遍会对理解 Redwood 包装层所隐藏的细节大有帮助。前置准备开始之前请依次完成以下步骤创建 Redwood 应用注册 Supabase 账户并创建组织与项目完成 Supabase 的 React Quick Start先直连 Supabase Client建立直观感受完成 Supabase 的 Redwood Quick Start观察与纯 React 用法的差异启动开发服务器yarn redwood dev认证术语梳理初次接触时认证领域的名词容易让人头晕。这里帮你理清一条主线Redwood 的 Supabase 认证客户端包装了 Supabase 的 GoTrueJS 客户端而后者是 Netlify GoTrueJS 客户端的分支它与 Netlify Identity 不同dbAuth 则是 Redwood 完全独立的一种认证方案。本教程暂不涉及 RBAC基于角色的访问控制。安装与初始化一条命令搞定配置有了 Supabase Quick Start 的知识储备回到我们创建好的 Redwood 应用。安装所需包并生成 Redwood Auth 的样板代码只需一条 CLI 命令yarn redwood setup auth supabase指定supabase作为 provider 后Redwood 会自动向应用写入必要的 Supabase 配置。在 CLI 源码中可以看到该命令在 packages/cli/src/commands/setup/auth/auth.js 中注册为setup auth provider的子命令执行时会动态加载redwoodjs/auth-supabase-setup包若未安装则自动以与框架一致的版本yarn add -D安装再调用其 handler 完成文件写入与代码修改。打开web/src/App.[js/tsx]检查你应该看到import { AuthProvider } from redwoodjs/auth import { createClient } from supabase/supabase-js import { FatalErrorBoundary, RedwoodProvider } from redwoodjs/web import { RedwoodApolloProvider } from redwoodjs/web/apollo import FatalErrorPage from src/pages/FatalErrorPage import Routes from src/Routes import ./index.css const supabaseClient createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY) const App () ( FatalErrorBoundary page{FatalErrorPage} RedwoodProvider titleTemplate%PageTitle | %AppTitle AuthProvider client{supabaseClient} typesupabase RedwoodApolloProvider Routes / /RedwoodApolloProvider /AuthProvider /RedwoodProvider /FatalErrorBoundary ) export default App核心动作是第 12 行的AuthProvider client{supabaseClient} typesupabase把用SUPABASE_URL和SUPABASE_KEY创建的 Supabase 客户端实例注入到整个组件树中供所有子组件通过useAuth钩子访问。在较新版本的 Redwood 中对应仓库当前的 auth.ts.template初始化方式稍有演进setup 会在web/src/auth.ts生成如下代码把客户端创建与AuthProvider/useAuth的装配封装在createAuth中页面侧则统一从src/auth导入import { createClient } from supabase/supabase-js import { createAuth } from redwoodjs/auth-supabase-web const supabaseClient createClient( process.env.SUPABASE_URL || , process.env.SUPABASE_KEY || ) export const { AuthProvider, useAuth } createAuth(supabaseClient)两种写法的本质相同最终都通过createAuth把 Supabase 客户端包装成 Redwood Auth 统一接口login、logout、signup、getToken等实现见 packages/auth-providers/supabase/web/src/supabase.ts。环境变量配置现在把 Supabase 的 URL、公共 API Key 和 JWT 密钥SUPABASE_URL、SUPABASE_KEY、SUPABASE_JWT_SECRET写入.env文件。这些信息可在 Supabase 管理控制台获取Project URL 与 API keyanon / public新建项目后控制台展示的项目 URL 和 API Key若页面刷新错过可在「Connecting to your new project」区域找到。JWT Secret位于左侧导航底部的「Project Settings齿轮图标」→「API」→ 向下滚动至「JWT Settings」下的「JWT Secret」。.env示例如下# .env (in your root project directory) SUPABASE_URLhttps://replacewithyoursupabaseurl.supabase.co SUPABASE_KEYeyJhb_replace_VCJ9.eyJy_with_your_wfQ.0Abb_anon_key_teLJs SUPABASE_JWT_SECRETeyJh_replace_CJ9.eyJy_with_your_NTQwOTB9.MGNZN_JWT_secret_JgErqxj4此外还要在redwood.toml中把SUPABASE_URL和SUPABASE_KEY加入 web 侧可见的环境变量白名单JWT Secret 仅用于 api 侧校验不需要暴露给浏览器[web] # ... includeEnvironmentVariables [SUPABASE_URL, SUPABASE_KEY]至此配置基本完成。还有一个可选项若注册流程不需要邮箱确认可在 Supabase 管理控制台Authentication Settings中关闭「Enable email confirmations」。源码视角Redwood Auth 如何包装 Supabase理解底层实现有助于排查问题。在 supabase.ts 中createAuthImplementation返回的 auth 实现把 Supabase SDK 的多种登录方式统一收敛到login方法通过credentials.authMethod分发到不同底层调用password→supabaseClient.auth.signInWithPassword(credentials)邮箱/手机号 密码登录oauth→supabaseClient.auth.signInWithOAuth(credentials)GitHub、Google 等第三方登录otp→supabaseClient.auth.signInWithOtp(credentials)魔法链接或一次性密码支持邮箱与手机sso→supabaseClient.auth.signInWithSSO(credentials)企业级单点登录实验性id_token→supabaseClient.auth.signInWithIdToken(credentials)用受支持厂商签发的 ID Token 登录实验性其他情况返回携带AuthError(Unsupported authentication method)的结果signup直接调用supabaseClient.auth.signUp(credentials)且若返回结果包含session即服务端开启了自动确认会同步写入auth-providercookielogout调用supabaseClient.auth.signOut()getToken与getUserMetadata都基于supabaseClient.auth.getSession()返回会话与用户元数据restoreAuthState则在 OAuth 或魔法链接回调重定向回站点时通过refreshSession()恢复会话并清理 URL 中的access_token、refresh_token等认证参数。setup 同时会生成 api 侧的 api/src/lib/auth.tsgetCurrentUser解析并解码 JWT 返回用户信息与可选角色requireAuth/hasRole/isAuthenticated供 service 层做登录与角色校验未登录抛AuthenticationError角色不符抛ForbiddenError。注意getCurrentUser的返回值会暴露给 web 端务必只返回安全的字段。注册页面Sign Up先生成注册页面yarn redwood generate page signup这会向路由文件添加一条注册路由并创建SignupPage组件。在web/src/pages/SignupPage/SignupPage.[js/tsx]中导入 Redwood Form 组件做一个最基础的表单import { Form, TextField, PasswordField, Submit } from redwoodjs/forms const SignupPage () { return ( h1Sign Up/h1 Form TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } export default SignupPage想要更精致的表单样式可参考 Redwood Form 文档与教程的表单章节。这里聚焦功能本身——为表单添加onSubmit// ... const SignupPage () { const onSubmit (data) { // do something here } return ( h1Sign Up/h1 Form onSubmit{onSubmit} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } //...要做的事是——注册。为此需要与AuthProvider /及其内部包装的 Supabase GoTrue-JS 客户端通信这就要用到useAuth钩子。导入useAuth并从中解构出client即我们传入的 Supabase GoTrue-JS 实例可调用其全部方法import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SignupPage () { const { client } useAuth() const onSubmit (data) { // do something here } return ( h1Sign Up/h1 Form onSubmit{onSubmit} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } export default SignupPage在onSubmit中通过client.auth.signUp()传入表单捕获的email与password来创建新用户import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SignupPage () { const { client } useAuth() const onSubmit async (data) { try { const response await client.auth.signUp({ email: data.email, password: data.password }) console.log(response: , response) } catch(error) { console.log(error: , error) } } return ( h1Sign Up/h1 Form onSubmit{onSubmit} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } export default SignupPage目前注册可用但仅把响应打印到控制台并不实用。接下来用React.useState()管理错误状态条件渲染错误消息并在每次提交前用setError(null)重置import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SignupPage () { const { client } useAuth() const [error, setError] React.useState(null) const onSubmit async (data) { setError(null) try { const response await client.auth.signUp({ email: data.email, password: data.password }) console.log(response: , response) response?.error?.message setError(response.error.message) } catch(error) { setError(error.message) } } return ( h1Sign Up/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } export default SignupPage错误有两种返回方式promise 正常兑现fulfillment时错误位于返回对象内的error属性中promise 被拒绝rejection时错误通过 promise 本身抛出由catch块捕获处理。再处理成功提交的情况若关闭了邮箱确认注册成功即等同于登录成功此时应把用户重定向回应用首页。先生成首页若还没有yarn redwood generate page home /然后从 Redwood Router 导入routes与navigate在注册成功后跳转import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth import { routes, navigate } from redwoodjs/router const SignupPage () { const { client } useAuth() const [error, setError] React.useState(null) const onSubmit async (data) { setError(null) try { const response await client.auth.signUp({ email: data.email, password: data.password }) response?.error?.message ? setError(response.error.message) : navigate(routes.home()) } catch(error) { setError(error.message) } } return ( h1Sign Up/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form / ) } export default SignupPage注册页完成注册表单、错误展示、成功后跳转首页一应俱全。登录页面Sign In先生成登录页yarn redwood generate page signin添加含email、password字段的基础表单、错误提示与空的onSubmitimport { Form, TextField, PasswordField, Submit } from redwoodjs/forms const SigninPage () { const [error, setError] React.useState(null) const onSubmit (data) { // do sign in here } return ( h1Sign In/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign In/Submit /Form / ) } export default SigninPage导入useAuth并解构出logInimport { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SigninPage () { const { logIn } useAuth() const [error, setError] React.useState(null) const onSubmit (data) { setError(null) // do sign in here } return ( h1Sign In/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign In/Submit /Form / ) } export default SigninPage与注册不同这次直接调用 Redwood Auth 的logIn函数而非经由client向其传入包含 email 与 password 的对象import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SigninPage () { const { logIn } useAuth() const [error, setError] React.useState(null) const onSubmit async (data) { setError(null) try { const response await logIn({ email: data.email, password: data.password }) // do something } catch(error) { setError(error.message) } } return ( h1Sign In/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign In/Submit /Form / ) } export default SigninPage登录成功后重定向回首页。从redwoodjs/router导入navigate与routes在await logIn之后使用import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth import { navigate, routes } from redwoodjs/router const SigninPage () { const { logIn } useAuth() const [error, setError] React.useState(null) const onSubmit async (data) { setError(null) try { const response await logIn({ email: data.email, password: data.password }) response?.error?.message ? setError(response.error.message) : navigate(routes.home()) } catch(error) { setError(error.message) } } return ( h1Sign In/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign In/Submit /Form / ) } export default SigninPage手册剩余部分与 Netlify GoTrue Auth 版本一致这正体现了 Redwood Auth 包装层的乐趣特定认证方案相关的代码只集中在上面几个位置其余部分可统一使用通用的 Redwood Auth 函数。在 Redwood 中logIn是统一入口除密码登录外它同样支持 OAuth、OTP、ID Token 与 SSO 等方式只需传入不同的authMethod对应源码中的credentials.authMethod分发逻辑。例如 GitHub OAuth 登录可写作logIn({ authMethod: oauth, provider: github })。登出按钮Sign Out登出是最容易实现的——只需调用useAuth的logOut方法。先生成组件yarn redwood generate component signoutBtn在web/src/components/SignoutBtn/SignoutBtn.js中渲染按钮并添加点击处理器const SignoutBtn () { const onClick () { // do sign out here. } return button onClick{() onClick()}Sign Out/button } export default SignoutBtn导入useAuth解构logOut并在onClick中调用import { useAuth } from redwoodjs/auth const SignoutBtn () { const { logOut } useAuth() const onClick () { logOut() } return button onClick{() onClick()}Sign Out/button } export default SignoutBtn这已经能工作但用户可能正处在受保护的页面登出后应将其导航离开当前页import { useAuth } from redwoodjs/auth import { navigate, routes } from redwoodjs/router const SignoutBtn () { const { logOut } useAuth() const onClick async () { await logOut() navigate(routes.home()) } return button onClick{() onClick()}Sign Out/button } export default SignoutBtn在底层logOut调用supabaseClient.auth.signOut()清除浏览器会话与 localStorage并触发SIGNED_OUT事件见 supabase.ts 中logout的实现。目前这个按钮还没有渲染到任何地方——下一步就把它接进根据认证状态切换的导航。认证状态导航Auth Links实现一段根据用户认证状态条件渲染的导航用户未登录时显示Sign Up与Sign In用户已登录时显示Log Out先生成导航组件yarn redwood generate component navigation在web/src/components/Navigation/Navigation.js中导入 Router 的Link组件与routes对象以及用于订阅认证状态的useAuthimport { Link, routes } from redwoodjs/router import { useAuth } from redwoodjs/auth const Navigation () { return nav/nav } export default Navigation从useAuth解构isAuthenticated并在条件语句中使用import { Link, routes } from redwoodjs/router import { useAuth } from redwoodjs/auth const Navigation () { const { isAuthenticated } useAuth() return ( nav {isAuthenticated ? ( // signed in - show the Sign Out button ) : ( // signed out - show the Sign Up and Sign In links )} /nav ) } export default NavigationRedwood Auth 基于 React 的 Context API 管理与广播认证状态因此可以放心只要组件位于AuthProvider /之下isAuthenticated就会始终是最新的——即使认证状态在组件树中的其他组件里发生变化React 也会自动重渲染出正确的组件。把登出按钮以及登录、注册链接放进条件块的对应分支import { Link, routes } from redwoodjs/router import { useAuth } from redwoodjs/auth import SignoutBtn from src/components/SignoutBtn/SignoutBtn const Navigation () { const { isAuthenticated } useAuth() return ( nav {isAuthenticated ? ( SignoutBtn / ) : ( Link to{routes.signup()}Sign Up/Link Link to{routes.signin()}Sign In/Link / )} /nav ) } export default Navigation导航组件已经可用还需要把它渲染到页面中。先生成一个名为 GlobalLayout 的布局yarn redwood generate layout global在生成的web/src/layouts/GlobalLayout/GlobalLayout中导入并渲染导航组件import Navigation from src/components/Navigation/Navigation const GlobalLayout ({ children }) { return ( header Navigation / /header main{children}/main / ) } export default GlobalLayout最后用 Router 的Set组件把每个页面高效地包裹进GlobalLayout更新web/src/Routes.[js/tsx]import { Router, Route, Set } from redwoodjs/router import GlobalLayout from src/layouts/GlobalLayout/GlobalLayout const Routes () { return ( Router Set wrap{GlobalLayout} Route path/ page{HomePage} namehome / Route path/signup page{SignUpPage} namesignup / Route path/signin page{SignInPage} namesignin / /Set Route notfound page{NotFoundPage} / /Router ) } export default Routes现在导航会根据认证状态渲染正确的链接与按钮登录后看到Sign Out按钮登出后看到Sign Up与Sign In链接。测试与验证认证实现的正确性保障仓库为 Supabase 认证实现提供了完整的单元测试见 packages/auth-providers/supabase/web/src/tests/supabase.test.tsx。这些用例覆盖了本手册涉及的全部核心场景可作为自测清单登录前isAuthenticated为false邮箱 密码注册含附加元数据、重定向 URL 两种变体后认证状态为true且currentUser.email与userMetadata正确密码登录后isAuthenticated为true登出后恢复为falsehasRole支持从 Supabase 的app_metadata.roles读取角色也支持通过useHasRole/useCurrentUser自定义钩子覆写默认行为OAuth、OTP、ID Token、SSO 四种logIn方式均能正确建立认证状态。此外supabase.middleware.test.tsx 验证了流式 SSR 场景下中间件认证middleware auth的行为。收尾与延伸至此我们已经完成了用 Redwood Auth 配置 Supabase GoTrue Auth创建注册页、登录页与登出按钮并把认证链接接入布局。配置、注册、登录、登出、状态化导航的完整闭环已经跑通。后续深入时值得留意的特性未来的实战手册可以逐个深挖认证状态变更监听可通过 Supabase 客户端的onAuthStateChange事件监听SIGNED_IN、SIGNED_OUT、TOKEN_REFRESHED、USER_UPDATED、PASSWORD_RECOVERY等事件需在useEffect中调用并记得退订。更多认证方式Passwordless输入邮箱获取魔法确认链接对应authMethod: otp第三方登录GitHub、Google 等对应authMethod: oauth手机一次性密码OTP使用刷新令牌refresh token登录——JWT 是认证实现的关键组成部分受保护页面在 api 侧通过requireAuth保护 service未认证用户将收到AuthenticationError。相关参考资源Redwood Supabase Auth 安装与设置文档版本 6.x 的 Supabase 认证专章Redwood Supabase Auth 客户端实现packages/auth-providers/supabase/web/src/supabase.tsSupabase 认证客户端使用与配置说明packages/auth-providers/supabase/web/README.mdsetup 命令注册源码packages/cli/src/commands/setup/auth/auth.js赞分享后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载相关推荐Redwood Supabase Auth 实战指南GoTrue 认证接入、注册登录与状态导航Redwood Supabase Auth 实战指南GoTrue 认证接入、注册登录与状态导航 本文是一份基于 Redwood 官方文档《Supabase后端前端Web框架开发工具Redwood 接入 Supabase Auth 完整实战从 setup auth 到注册、登录、登出与条件导航Redwood 接入 Supabase Auth 完整实战从 setup auth 到注册、登录、登出与条件导航 本篇指南以 Redwood 官方 How t后端前端Web框架开发工具Repomix 遠端 GitHub 倉庫處理指南從 --remote 打包到遠端設定信任機制Repomix 遠端 GitHub 倉庫處理指南從 remote 打包到遠端設定信任機制 Repomix 可以把整個程式碼庫打包成單一、對 AI 友善的檔案后端前端Web框架开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表