首页/新闻资讯/正文详情

在 Redwood 中使用 GoTrue 构建自托管身份认证(Sign Up / Sign In / Sign Out 全流程)

发布时间:2026/9/25 8:05:11 来源:云帆数科 栏目:资讯中心
在 Redwood 中使用 GoTrue 构建自托管身份认证(Sign Up / Sign In / Sign Out 全流程)
后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载这篇指南将带你脱离 Netlify Identity Widget 的“一键式”束缚改用 GoTrue-JS 客户端库直接对接 Netlify Identity 的 GoTrue API在 Redwood 应用中完全掌控认证界面与交互流程。读完本文你将掌握如何用yarn redwood setup auth goTrue生成认证配置、手写 Sign Up / Sign In 表单、实现 Sign Out 按钮并通过useAuth的认证状态在导航中条件渲染正确的操作入口。本文以 Redwood 官方文档《GoTrue Auth》为基础并结合当前仓库源码CLI 认证脚手架、Netlify 认证提供者实现进行纵深讲解。为什么放弃 Widget、拥抱 GoTrue-JS如果你已完成 Redwood 教程的认证章节会发现用 Netlify Identity Widget 几分钟内就能给应用加上认证。但 Widget 是一套封装好的弹窗交互你很难定制界面与行为。GoTrue-JS 是 Netlify Identity 的 GoTrue API 的官方 JavaScript 客户端库它把注册、登录、登出、令牌刷新等能力以编程接口的形式暴露出来让你完全自定义认证表单的 UI 与校验逻辑在开发阶段保持较低的接入复杂度复用 Redwood 的useAuth钩子以统一方式订阅认证状态。在本文的实操中我们将完成四件事用 Redwood CLI 生成 GoTrue 认证配置创建 Sign Up注册表单创建 Sign In登录表单创建 Sign Out登出按钮添加根据认证状态显示正确按钮的导航链接。前置条件动手之前请确保已完成以下步骤创建一个 Redwood 应用注册 Netlify 账户启用 Netlify Identity启动开发服务器yarn redwood dev。启用 Netlify Identity登录 Netlify进入站点Dashboard打开Identity标签页点击Enable Identity。启用后你会看到形如https://my-bodacious-app.netlify.app/.netlify/identity的 Identity API 端点。请把该地址复制保存稍后实例化 GoTrue-JS 时需要用到。生成认证配置安装所需依赖包并生成 Redwood Auth 的样板代码只需要一条 CLI 命令yarn redwood setup auth goTrue指定goTrue作为提供者后Redwood 会自动把 GoTrue-JS 的配置写入web/src/App.js。打开该文件你应该看到import { AuthProvider } from redwoodjs/auth import GoTrue from gotrue-js import { FatalErrorBoundary } from redwoodjs/web import { RedwoodApolloProvider } from redwoodjs/web/apollo import FatalErrorPage from src/pages/FatalErrorPage import Routes from src/Routes import ./index.css const goTrueClient new GoTrue({ APIUrl: https://MYAPP.netlify.app/.netlify/identity, setCookie: true, }) const App () ( FatalErrorBoundary page{FatalErrorPage} AuthProvider client{goTrueClient} typegoTrue RedwoodApolloProvider Routes / /RedwoodApolloProvider /AuthProvider /FatalErrorBoundary ) export default App现在把刚才复制的 API 端点替换到APIUrl中// imports... const goTrueClient new GoTrue({ APIUrl: https://gotrue-recipe.netlify.app/.netlify/identity, setCookie: true, })配置到此结束。核心要点是AuthProvider接收clientGoTrue-JS 实例和typegoTrue两个关键属性之后整个组件树都能通过useAuth访问该客户端及其全部方法。关于“goTrue”的现状说明当前仓库的 CLI 认证脚手架 中goTrue已作为“不再单独支持”的历史提供者被重定向redirectCommand(goTrue)官方现在建议改用netlify基于 netlify-identity-widget或 Custom Auth。但 GoTrue 的接入思路——用统一clienttype注入AuthProvider、通过useAuth消费——在 Redwood 的所有认证提供者中一脉相承理解本文流程仍可直接迁移。在 v6.x 时代setup auth goTrue会直接生成上面的代码。Sign Up注册页先确保在 Netlify Dashboard 的Identity Settings and usage中进入Emails Confirmation template Edit settings勾选Allow users to sign up without verifying their email address并保存。这样首版注册流程不需要处理邮箱确认其余进阶能力邮箱确认、密码找回等留待后续扩展。生成注册页yarn redwood generate page Signup该命令会为 Signup 添加一条 路由并创建 SignupPage 组件。在web/src/pages/SignupPage/SignupPage.js中导入 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 SignupPageTextField与PasswordField的name属性会直接映射到onSubmit回调收到的数据对象字段上这是 Redwood Form 的核心约定。接入 useAuth 与注册逻辑接下来让表单在提交时真正执行注册。先为Form增加onSubmit处理函数// imports... 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 /及 GoTrue-JS 客户端通信的通道——正是useAuth钩子。它让我们订阅认证状态及其属性此处通过它拿到clientGoTrue-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.signup(email, password)创建新用户import { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth const SignupPage () { const { client } useAuth() const onSubmit (data) { client .signup(data.email, data.password) .then((res) console.log(res)) .catch((error) console.log(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 (data) { setError(null) client .signup(data.email, data.password) .then((res) console.log(res)) .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再从 Redwood Router 导入routes与navigate在注册成功的then回调中跳转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 (data) { setError(null) client .signup(data.email, data.password) .then(() navigate(routes.signin())) .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至此注册页完成提交表单 → 调用client.signup()→ 失败显示错误成功跳转登录页。Sign In登录页在上一节生成的 SigninPage 中加入包含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和一个remember布尔值控制是否记住登录状态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 (data) { setError(null) logIn({ email: data.email, password: data.password, remember: true }) .then(() { // 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登录成功后把用户带回首页。先生成首页如果还没有yarn redwood generate page Home /在 SigninPage 中导入navigate与routes在then回调中跳转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 (data) { setError(null) logIn({ email: data.email, password: data.password, remember: true }) .then(() 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登录页完成提交表单 →logIn({ email, password, remember })→ 失败显示错误成功跳转首页。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 () { logOut().then(() navigate(routes.home())) } return button onClick{() onClick()}Sign Out/button } export default SignoutBtn此时logOut()完成后会返回一个 Promise随后跳转到首页。Auth Links根据认证状态渲染导航现在实现条件导航未登录时显示Sign Up与Sign In已登录时显示Log Out。先生成导航组件yarn redwood generate component Navigation在web/src/components/Navigation/Navigation.js中从redwoodjs/router导入 Link 组件与 routes 对象并导入useAuth以便订阅认证状态import { 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 管理并广播认证状态因此isAuthenticated始终是最新的——即使认证状态在组件树中其他位置发生变化只要该组件是AuthProvider /的子节点React 也会自动重新渲染出正确的组件。接下来导入登出按钮并把 Sign In / Sign Up 链接放进条件分支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把导航挂进全局布局导航组件还需渲染到应用中。先生成一个名为 Global 的布局yarn redwood generate layout Global在web/src/layouts/GlobalLayout/GlobalLayout.js中导入并渲染导航组件import Navigation from src/components/Navigation/Navigation const GlobalLayout ({ children }) { return ( header Navigation / /header main{children}/main / ) } export default GlobalLayout最后用 GlobalLayout 包裹每个生成的页面Homeimport GlobalLayout from src/layouts/GlobalLayout/GlobalLayout const HomePage () { return ( GlobalLayout h1Home/h1 pMy Gotrue Redwood Auth/p /GlobalLayout ) } export default HomePageSign Upimport { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth import { routes, navigate } from redwoodjs/router import GlobalLayout from src/layouts/GlobalLayout/GlobalLayout const SignupPage () { const { client } useAuth() const [error, setError] React.useState(null) const onSubmit (data) { setError(null) client .signup(data.email, data.password) .then(() navigate(routes.signin())) .catch((error) setError(error.message)) } return ( GlobalLayout h1Sign Up/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign Up/Submit /Form /GlobalLayout ) } export default SignupPageSign Inimport { Form, TextField, PasswordField, Submit } from redwoodjs/forms import { useAuth } from redwoodjs/auth import { navigate, routes } from redwoodjs/router import GlobalLayout from src/layouts/GlobalLayout/GlobalLayout const SigninPage () { const { logIn } useAuth() const [error, setError] React.useState(null) const onSubmit (data) { setError(null) logIn({ email: data.email, password: data.password, remember: true }) .then(() navigate(routes.home())) .catch((error) setError(error.message)) } return ( GlobalLayout h1Sign In/h1 Form onSubmit{onSubmit} {error p{error}/p} TextField nameemail placeholderemail / PasswordField namepassword placeholderpassword / SubmitSign In/Submit /Form /GlobalLayout ) } export default SigninPage现在导航会根据认证状态渲染正确的链接和按钮用户登录后看到Sign Out按钮登出后看到Sign Up与Sign In链接。源码视角认证提供者如何工作为加深理解可以对照当前仓库中 Redwood 官方认证提供者的实现。以 Netlify 提供者的前端实现 为例它的核心是createAuthImplementation返回的一组接口包括login打开登录弹窗并监听login/close/error事件返回 Promise 形式的用户对象logout调用netlifyIdentity.logout()在logout事件触发时 resolvesignup打开注册弹窗关闭时 resolvegetToken调用netlifyIdentity.refresh()仅在令牌过期时真正刷新返回access_tokengetUserMetadata/restoreAuthState返回当前用户。createAuth(implementation)会把这份实现接入 Redwood 的useAuth这正是我们页面中logIn、logOut、client、isAuthenticated等 API 的底层来源。GoTrue-JS 时代的接入方式AuthProvider client{goTrueClient} typegoTrue与该模式完全一致Redwood 只负责“翻译”认证客户端的能力认证的存储、刷新与校验仍由提供方完成。总结至此我们已经用yarn redwood setup auth goTrue配置了 GoTrue 与 Redwood Auth 的对接创建了 Sign Up 页面含错误提示与成功跳转创建了 Sign In 页面logIn({ email, password, remember })登录并跳转首页创建了 Sign Out 按钮logOut()后导航回首页在 GlobalLayout 中挂载了条件导航根据isAuthenticated渲染正确操作入口。这套“底层认证客户端 RedwooduseAuth统一接口 自定义表单”的模式可以平滑迁移到 Redwood 当前支持的任意认证提供者如 Netlify、Supabase、Auth0 等是深入理解 Redwood 认证体系的良好起点。后续还可以继续扩展邮箱确认、密码找回等进阶功能。赞分享后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载相关推荐终极指南如何使用Sign-In with Ethereum实现去中心化身份认证终极指南如何使用Sign In with Ethereum实现去中心化身份认证 Sign In with EthereumSIWE正在彻底改变我们进行身份Noodle平台认证系统实现从Sign-In到权限管理全流程Noodle平台认证系统实现从Sign In到权限管理全流程 你是否还在为开源项目的用户认证系统搭建而烦恼Noodle平台作为开源教育平台Open Sou教育前端后端Barter-rs多策略并发执行提升交易效率的高级技巧Barter rs多策略并发执行提升交易效率的高级技巧 Barter rs是一个开源的Rust框架专为构建事件驱动的实时交易和回测系统而设计。多策略并发执行金融科技上一篇GPT-NeoX数据增强终极指南文本扰动与噪声注入技术详解下一篇如何用柚坛工具箱NT轻松搞定Android设备刷机、应用管理与调试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

AI工程落地指南:从arxiv-cs.AI论文到可运行RAG与Agent代码
AI工程落地指南:从arxiv-cs.AI论文到可运行RAG与Agent代码

1. 这不是一份“论文清单”,而是一份AI工程实践的实时快照如果你点开过arxiv-cs.AI这个分类页面,大概率会陷入一种熟悉的眩晕感:每天新增几十甚至上百篇论文,标题里塞满了LLM、RAG、Multi-Agent、Agentic、Ontology、Self-Refine…… · 2026/9/25 8:05:11

Atlas 300V 24G部署YOLO:从环境搭建到推理加速的实战指南
Atlas 300V 24G部署YOLO:从环境搭建到推理加速的实战指南

Atlas 300V 24G这个型号最近被问得特别多,尤其是在“能不能跑YOLO”这个问题上。我自己的测试环境里长期插着这张卡,从YOLOv5一路做到YOLOv8、YOLOv10,踩过不少坑,也总结出了一套比较顺手的部署流程。这篇东西就围绕atlas部署yolo… · 2026/9/25 8:05:11

AgentScope多智能体框架实战:从消息传递到RAG服务化
AgentScope多智能体框架实战:从消息传递到RAG服务化

1. 为什么我要花时间聊 AgentScope 这个系统第一次接触 AgentScope 是在一个需要快速搭建多智能体协作原型的项目里。当时团队面临的核心问题是:业务侧希望用多个 AI 角色分别承担信息检索、数据清洗、逻辑推理和结果汇总,但市面上大多数框架要么把智能体… · 2026/9/25 8:05:05

Atlas 300V Pro 上部署 YOLOv5:CANN 环境与模型转换完整实践
Atlas 300V Pro 上部署 YOLOv5:CANN 环境与模型转换完整实践

上周隔壁组的同事拿着两块贴着Atlas 300V Pro标签的板卡过来问我:“这卡是运算加速卡吗?是不是能像 4090 一样直接跑 YOLO?”这个问题我当时没法用一句话回答,因为把它当成“加强版显卡”理解,后面每一步都会走偏。为了… · 2026/9/25 8:33:34

神经网络实战入门:非算法工程师的四步落地法
神经网络实战入门:非算法工程师的四步落地法

1. 这不是玄学,是被现实倒逼出来的技术自救“被逼搞上神经网络这东西!要命啊!?有没同道中人!”——这句话我第一次在技术群看到时,手里的咖啡差点洒出来。不是因为夸张,而是太真实了。它背后站着… · 2026/9/25 8:33:34

Spring Boot新增字段全链路指南:从数据库到接口的完整实操
Spring Boot新增字段全链路指南:从数据库到接口的完整实操

做后端开发这些年,每次碰到“加个字段”这种需求,我都会下意识地把问题拆成一套完整动作来对待。很多人一听就笑了:不就是数据库里ALTER TABLE加一列,实体类加一个属性,顶多再改一下查询SQL吗?但实际上&… · 2026/9/25 8:33:28

CRM系统选型与自建:从免费SaaS到永久在线私人部署全指南
CRM系统选型与自建:从免费SaaS到永久在线私人部署全指南

销售团队最怕的不是单子少,而是客户资料全散在各部门的聊天记录里。换一个销售跟进,客户前面聊到哪一步根本接不上;老板想拉一份业绩统计,翻半天表格还凑不齐。DeskcommCRM做的事情,就是把这些散落的信息统一收进一套线… · 2026/9/25 8:33:22

唐诗三百首数据集:从CSV到MySQL的导入与文本挖掘实战
唐诗三百首数据集:从CSV到MySQL的导入与文本挖掘实战

简介:一份面向中文古典诗词数据应用的《唐诗三百首》结构化数据集,涵盖320条诗歌记录,适合开发者快速搭建诗词查询库、教师制作教学课件,以及文本分析人员用作NLP语料;资源压缩包共4个文件,分别提供sql、js… · 2026/9/25 8:33:22

集装箱彩钢房实力厂家推荐 彩钢房生产厂家联系方式与对比参考
集装箱彩钢房实力厂家推荐 彩钢房生产厂家联系方式与对比参考

集装箱彩钢房实力厂家推荐:彩钢房生产厂家联系方式与对比参考做工程临建的朋友都知道,选一家靠谱的彩钢房、集装箱生产厂家,能避开施工中大半的麻烦,潍坊晟兴活动板房有限公司深耕山东装配式临建领域,主打用料扎实合规… · 2026/9/25 8:33:22

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码