news 2026/9/15 18:37:15

Wasp 教程:为全栈应用添加用户名密码认证(Auth)完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Wasp 教程:为全栈应用添加用户名密码认证(Auth)完整实战

Wasp 教程:为全栈应用添加用户名密码认证(Auth)完整实战

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

本篇技术指南以 Wasp 官方教程的第 7 步(Adding Authentication)为核心,围绕当前仓库中的 TodoApp 示例 展开,讲解如何用 Wasp 的声明式配置为全栈应用一键接入完整的用户名密码认证体系:从创建UserEntity、配置app.auth、生成登录/注册页面,到用authRequired保护路由、实现按用户隔离的任务数据,最后加入登出功能。读完本文,你将掌握 Wasp 认证的完整落地流程,并理解其背后的数据模型与源码级实现原理。

认证:Wasp 的一等公民能力

大多数现代应用都需要"创建用户、登录、管理会话"这整套能力。在传统全栈开发中,这往往意味着引入额外的认证库、手写会话管理、搭建密码哈希与校验流程;而在 Wasp 中,认证是框架的一等公民特性(first-class auth support),你只需要做少量声明式配置,Wasp 就会在后台自动生成:

  • 完整的认证 UI(登录、注册表单);
  • 一个logout()action;
  • 一个 React HookuseAuth()
  • Queries 和 Actions 中可用的context.user
  • 密码哈希存储与基于 Session 的会话管理。

以 TodoApp 教程为例,接入认证总共需要完成以下清单:

  • 创建UserEntity;
  • app.auth中启用"用户名密码"认证;
  • 添加登录与注册页面;
  • 设置主页面authRequired以要求登录;
  • 建立UserTask之间的关联关系;
  • 修改 Queries 与 Actions,使用户只能看到和修改自己的任务;
  • 添加登出按钮。

第一步:创建 User Entity

Wasp 管理认证时,会自动在后台创建与认证相关的实体(AuthAuthIdentitySession等),这部分不需要你操心(想深入了解可阅读 auth entities 文档)。你只需要自己添加一个UserEntity,用来记录"谁拥有哪些任务":

// ... model User { id Int @id @default(autoincrement()) }

在仓库的 TodoApp 示例 schema.prisma 中可以看到最终形态:User拥有id主键,并进一步声明了tasks Task[]反向关系字段;Task通过user/userId外键关联回User

第二步:在 main.wasp 中开启认证

接下来,告诉 Wasp 使用全栈认证功能。以 v0.15 教程采用的.waspDSL 语法为例:

app TodoApp { wasp: { version: "^0.15.0" }, title: "TodoApp", auth: { // Tells Wasp which entity to use for storing users. userEntity: User, methods: { // Enable username and password auth. usernameAndPassword: {} }, // We'll see how this is used in a bit. onAuthFailedRedirectTo: "/login" } } // ...

这三个配置项各自承担关键职责:

  • userEntity: User:指定用于存放业务用户的实体,Wasp 会把它与内部认证实体(AuthAuthIdentitySession)关联起来;
  • methods: { usernameAndPassword: {} }:启用"用户名 + 密码"认证方式;
  • onAuthFailedRedirectTo: "/login":当认证失败(如未登录访问受保护页面)时重定向到的路由。

值得注意的是,当前仓库的主线版本已迁移到新的 TypeScript spec(TS spec)语法,TodoApp 的 main.wasp.ts 中对应的声明写法如下,二者表达的是同一套认证配置:

import { action, app, page, query, route } from "@wasp.sh/spec"; export default app({ name: "TodoApp", wasp: { version: "0.26.0" }, title: "TodoApp", auth: { userEntity: "User", methods: { usernameAndPassword: {}, }, onAuthFailedRedirectTo: "/login", }, // ... });

更新数据库:wasp db migrate-dev

完成配置后,不要忘记同步数据库 schema:

wasp db migrate-dev

这条命令会为 Wasp 内部认证体系创建数据表。从仓库中的认证迁移文件 20240716203310_auth/migration.sql 可以看到,Wasp 实际生成了三张核心表:

  • Auth:用户认证主记录,通过userId外键一对一关联到你的User表,删除用户时级联删除(ON DELETE CASCADE);
  • AuthIdentity:认证身份表,主键为(providerName, providerUserId)providerData字段存放该提供方特有的数据(如密码哈希等,默认'{}'),支持未来扩展多种登录方式;
  • Session:会话表,包含expiresAt过期时间和指向AuthuserId外键,为"记住登录状态"提供底层支撑。

这也是为什么教程末尾提示你"可能看到一些额外的 Prisma 模型"——它们正是 Wasp 为你自动创建的认证基础设施。

第三步:添加登录与注册页面

表单由 Wasp 自动生成,你只需要定义承载表单的页面。先在 Wasp 文件中声明路由和页面:

// ... route SignupRoute { path: "/signup", to: SignupPage } page SignupPage { component: import { SignupPage } from "@src/SignupPage" } route LoginRoute { path: "/login", to: LoginPage } page LoginPage { component: import { LoginPage } from "@src/LoginPage" }

然后实现被 import 的 React 组件。登录页直接渲染 Wasp 提供的LoginForm

import { Link } from 'react-router-dom' import { LoginForm } from 'wasp/client/auth' export const LoginPage = () => { return ( <div style={{ maxWidth: '400px', margin: '0 auto' }}> <LoginForm /> <br /> <span> I don't have an account yet (<Link to="/signup">go to signup</Link>). </span> </div> ) }

注册页结构几乎相同,只是换成SignupForm

import { Link } from 'react-router-dom' import { SignupForm } from 'wasp/client/auth' export const SignupPage = () => { return ( <div style={{ maxWidth: '400px', margin: '0 auto' }}> <SignupForm /> <br /> <span> I already have an account (<Link to="/login">go to login</Link>). </span> </div> ) }

这两个页面的完整实现可以在仓库的 LoginPage.jsx 与 SignupPage.jsx 中查看(对应 TypeScript 版本见 TodoAppTs 示例)。

如果你使用 TypeScript,还可以受益于 Wasp 类型安全的Link组件和routes对象,详见类型安全链接文档。

LoginFormSignupForm内部由 Wasp 生成器模板提供,例如在 LoginSignupForm.tsx 中,表单通过useAuthContext()获取认证状态、错误消息与加载状态,统一驱动登录/注册的交互逻辑。

第四步:让主页面要求认证

我们不希望未登录用户访问主页(因为他们在那里无法创建任务)。在页面声明中加上authRequired: true即可将其设为私有页面:

// ... page MainPage { authRequired: true, component: import { MainPage } from "@src/MainPage" }

authRequiredtrue时:

  • 未认证用户访问该页面会被重定向到/login,这正是app.auth.onAuthFailedRedirectTo配置生效的地方;
  • 页面的 React 组件会自动收到一个user对象 prop:
export const MainPage = ({ user }) => { // Do something with the user // ... }

TypeScript 下使用wasp/auth提供的AuthUser类型进行标注:

import { AuthUser } from 'wasp/auth' export const MainPage = ({ user }: { user: AuthUser }) => { // Do something with the user // ... }

在 TodoApp 的 main.wasp.ts 中,这一配置以page(MainPage, { authRequired: true })的形式挂载到根路由/上。

现在可以实际测试了:访问应用主页/,会被重定向到/login;去注册页创建一个账号后,会自动回到主页并看到 TODO 列表。如果此时用wasp db studio打开数据库,会看到User实体与Task实体并存,且认证体系相关的表也各就各位。

第五步:建立 User 与 Task 的一对多关系

接下来定义用户与任务的一对多关系(关于关系建模可参考 Prisma 官方文档的 Relations 章节):

// ... model User { id Int @id @default(autoincrement()) tasks Task[] } model Task { id Int @id @default(autoincrement()) description String isDone Boolean @default(false) user User? @relation(fields: [userId], references: [id]) userId Int? }

同样,修改 Entity 后必须迁移数据库:

wasp db migrate-dev

仓库中的迁移文件 20240716203532_task_users/migration.sql 展示了这次迁移的实际 SQL:由于 SQLite 不支持原地修改表结构,Prisma 采用"重建表"策略——创建带userId的新Task表、把旧数据(descriptionidisDone)复制过去、再删除旧表重命名,外键约束为ON DELETE SET NULL

需要特别说明:这里把useruserId设为可选(?),是为了让数据库中已有的、尚未分配用户的旧任务得以保留。但这并非推荐做法——它允许"任务不属于任何人"这种非预期状态。正常情况下应当通过数据迁移妥善处理存量数据(哪怕只是全部删除)。教程出于简化目的选择了可选字段方案。

第六步:更新 Queries 与 Actions 校验用户

认证只是第一步,关键是要让查询和操作只作用于当前登录用户自己的数据。修改getTasks,拒绝未认证用户,并只返回当前用户的任务:

import { HttpError } from 'wasp/server' export const getTasks = async (args, context) => { if (!context.user) { throw new HttpError(401) } return context.entities.Task.findMany({ where: { user: { id: context.user.id } }, orderBy: { id: 'asc' }, }) }

相应地修改两个 Action。createTask在创建任务时通过user: { connect: { id: context.user.id } }把任务归属到当前用户;updateTask则在where中同时限定任务 id 和用户 id,确保只能更新自己的任务:

import { HttpError } from 'wasp/server' export const createTask = async (args, context) => { if (!context.user) { throw new HttpError(401) } return context.entities.Task.create({ data: { description: args.description, user: { connect: { id: context.user.id } }, }, }) } export const updateTask = async (args, context) => { if (!context.user) { throw new HttpError(401) } return context.entities.Task.updateMany({ where: { id: args.id, user: { id: context.user.id } }, data: { isDone: args.isDone }, }) }

一个值得注意的细节:updateTask从 Prisma 的update改成了updateMany。原因是 Prisma 的update不允许在where中同时组合主键id和关联字段user,而updateMany支持任意组合条件,从而实现了"只能更新属于自己的任务"这一安全约束。

这些代码与仓库中 queries.js 和 actions.js 的实际实现完全一致(TypeScript 版本中还会用wasp/server/operations导出的GetTasksCreateTaskUpdateTask类型为操作签名做类型约束)。

做完这些改动,每个用户都将拥有一个仅自己可见、仅自己可编辑的任务列表。可以用wasp db studio创建几个用户并分别添加任务验证效果。

第七步:添加登出按钮

最后加上登出功能。从wasp/client/auth导入logout并绑定到按钮点击事件:

// ... import { logout } from 'wasp/client/auth' //... const MainPage = () => { // ... return ( <div> // ... <button onClick={logout}>Logout</button> </div> ) }

在 TodoApp 的 MainPage.jsx 中,登出按钮与任务列表、新建任务表单同处一页:logout直接作为onClick处理器传入,点击后 Wasp 会自动清除会话并触发onAuthFailedRedirectTo指定的重定向。

至此,完整的认证系统已经就绪,TodoApp 正式成为多用户应用!

端到端验证:认证流程的自动化测试

仓库还提供了 Playwright 端到端测试,用于验证这套认证流程的真实行为。在 simple.spec.ts 中可以看到完整的认证 + 业务闭环:

  1. 注册流程:访问/signup,填写随机生成的用户名密码并提交,断言 URL 变为/(说明注册成功后自动登录并跳转到受保护主页);点击 Logout 后断言回到/login
  2. 登录失败场景:用错误密码登录,断言页面出现 "Invalid credentials" 提示;
  3. 登录成功与任务操作:用正确凭据登录回到/,新建一个随机任务名并断言其渲染到页面上,勾选任务复选框后刷新页面,断言复选框仍处于勾选状态(证明状态已持久化到数据库)。

配套的 helpers.ts 揭示了 Wasp 生成的表单细节:注册表单标题为 "Create a new account"、用户名输入框name="username"、密码输入框类型为password;登录表单标题为 "Log in to your account"、提交按钮文本为 "Log in"。这些断言同时验证了LoginForm/SignupForm生成的 DOM 结构与交互行为,是理解认证 UI 的绝佳参考。

延伸:更多认证方式与后续学习

Wasp 的认证体系并不局限于用户名密码。通过调整auth.methods配置,你还可以接入 Google 登录、GitHub 登录 以及邮箱认证。底层机制保持一致:AuthIdentity表的(providerName, providerUserId)复合主键正是为多认证方式共存而设计的——同一用户可以拥有多个身份来源。

想继续深入,可以参考:

  • Wasp 官方 Starter Templates,获得带认证的完整项目起步模板;
  • 本仓库的 examples 目录 下的其他示例,如 waspello(看板应用)和 ask-the-documents(含邮箱登录与社交登录),展示认证在生产级示例中的真实用法;
  • Web Sockets 文档,构建实时多用户应用。

回顾整个流程:声明一个UserEntity、配置app.auth、写两个页面组件、给页面加authRequired、建立 Entity 关系、在 Queries/Actions 中校验context.user、加上登出按钮——Wasp 负责了其余所有繁重工作,包括密码哈希、会话管理、认证 UI 生成与数据库表结构。这正是"batteries-included"框架在认证这一复杂全栈能力上的价值所在。

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:36:07

Spring Boot食堂预约点餐系统源码拆解:订单状态机与防超卖设计

简介&#xff1a;面向计算机类毕业设计的Spring Boot高校食堂移动预约点餐系统源码包&#xff0c;适合学生参考学习、课程设计及全栈项目实战。实现以后端Java源码与前端Vue组件为主&#xff0c;配合微信小程序页面&#xff0c;覆盖登录认证、餐品浏览、预约下单、订单管理等常…

作者头像 李华
网站建设 2026/9/15 18:35:54

DiceDB JSON.ARRAPPEND 命令详解:向 JSON 数组尾部追加元素

DiceDB JSON.ARRAPPEND 命令详解&#xff1a;向 JSON 数组尾部追加元素 【免费下载链接】dicedb Open-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers. 项目地址: https://gitcode.com/GitHub_Trending/dic…

作者头像 李华
网站建设 2026/9/15 18:31:35

北京学会网站建设完整流程拆解:告别模板丑站,30天上线实录

北京学会网站建设完整流程拆解:告别模板丑站,30天上线实录 还在为找到的模板网站太丑、功能不够用而头疼吗?很多机构负责人拿到模板后,改改颜色就算完事,结果上线后客户觉得不专业,自己看着也难受。 这种“套壳”思维在学术和机构类网站建设中是死穴。今天咱们不谈虚的,直接复盘一个真实的 北京学会网站建设…

作者头像 李华
网站建设 2026/9/15 18:31:19

Flink实时风控系统落地复盘:特征计算、规则热更新与排障实践

把Flink接进风控系统之后&#xff0c;我最大的一个感悟是&#xff1a;实时风控这个事的难点&#xff0c;从来不在Flink本身。框架的API、窗口、状态管理&#xff0c;熟读文档总能学会&#xff1b;真正让团队掉进坑里的&#xff0c;是那些藏在"实时"二字背后的数据对齐…

作者头像 李华
网站建设 2026/9/15 18:30:31

HTML打包EXE全攻略:制作免安装绿色版与踩坑指南

上周同事拿U盘过来找我&#xff0c;说之前那个HTML小工具在这台电脑上打开是白屏。我看了一下&#xff0c;原因很简单&#xff1a;他直接把HTML文件拷过去了&#xff0c;CSS引用的本地路径全断了。这让我又一次动了把HTML一键打包成EXE的念头——做一个双击就能用的工具&#x…

作者头像 李华
网站建设 2026/9/15 18:30:14

OpenClaw模型量化:对称与非对称量化技术解析

1. OpenClaw模型量化中的量化方式解析OpenClaw作为当前热门的模型优化框架&#xff0c;其量化功能一直是开发者关注的焦点。在实际部署中&#xff0c;量化技术能显著减小模型体积、提升推理速度&#xff0c;而对称量化和非对称量化则是两种最基础的量化策略。1.1 对称量化的技术…

作者头像 李华