Wasp 认证实战:为 TodoApp 接入用户名密码登录与多用户数据隔离

发布时间:2026/9/15 10:35:20
Wasp 认证实战:为 TodoApp 接入用户名密码登录与多用户数据隔离 Wasp 认证实战为 TodoApp 接入用户名密码登录与多用户数据隔离【免费下载链接】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 官方教程《Adding Authentication》为核心讲解如何在 Wasp 应用中一键接入完整的前后端认证系统创建User实体、在main.wasp中声明认证配置、生成登录/注册页面、用authRequired保护路由并改造 Query/Action 实现每个用户只能看到和操作自己的任务的多用户数据隔离。读完本篇你将掌握 Wasp 声明式认证的完整落地流程并理解其底层context.user、HttpError、Auth 实体等实现机制可直接复用到任何 Wasp 项目中。认证接入总览需要完成的七件事大多数现代应用都需要创建用户并验证其身份Wasp 将这一能力做成了一等公民first-class auth support。要为 TodoApp 加入用户系统按以下清单逐步推进即可创建User实体告诉 Wasp 启用用户名 密码认证添加登录页与注册页将主页设为需要认证才能访问在User与Task实体之间建立关联修改 Query 和 Action让用户只能查看和修改自己的任务添加登出按钮对照仓库中的完整实现TodoAppTs 示例examples/tutorials/TodoAppTs/main.wasp.ts、examples/tutorials/TodoAppTs/schema.prisma正是这七步的最终成果可作为每一步的参照答案。第一步创建 User 实体由于 Wasp 全权托管认证它会在后台自动为你创建与认证相关的实体Auth、AuthIdentity、Session等。你唯一需要做的是添加一个User实体用于记录任务归属于谁// ... model User { id Int id default(autoincrement()) }在这一步User实体先保持最小化只有一个自增主键。Wasp 会自动建立User与后台 Auth 实体之间的连接把用户身份数据如用户名、密码哈希与你的业务实体关联起来。关于 Wasp 在后台自动创建的那些 Prisma 模型Auth、AuthIdentity、Session现阶段不需要关心其内部结构如果想深入了解可阅读 Auth 实体文档其中详细说明了每种认证方式对应的数据结构以及客户端/服务端拿到的AuthUser对象上identities字段的形态。第二步在 main.wasp 中开启认证接下来在 Wasp 配置文件中启用全栈认证app TodoApp { wasp: { version: {latestWaspVersion} }, title: TodoApp, auth: { // Tells Wasp which entity to use for storing users. userEntity: User, methods: { // Enable username and password auth. usernameAndPassword: {} }, // Well see how this is used in a bit. onAuthFailedRedirectTo: /login } } // ...各配置项的含义如下配置项作用userEntity: User指定用于存储用户的实体Wasp 会把登录用户与你定义的业务实体关联起来methods: { usernameAndPassword: {} }启用用户名 密码认证方式onAuthFailedRedirectTo: /login未认证用户访问受保护资源时的重定向地址稍后会用到这段声明式配置在 Wasp 编译器层面有明确的类型定义支撑。在 waspc/src/Wasp/AppSpec/App/Auth.hs 中可以看到Auth记录类型确实由userEntity、methods、onAuthFailedRedirectTo等字段构成而AuthMethods则通过Maybe UsernameAndPasswordConfig承载usernameAndPassword配置——这就是main.wasp中每个字段最终被解析校验的位置。修改配置后必须更新数据库结构wasp db migrate-dev执行完这一步Wasp 会自动生成一系列认证能力Auth UI现成的登录与注册表单组件Auth UI 文档logout()action服务端登出操作React hookuseAuth()在客户端获取当前登录用户context.user在 Query 和 Action 的服务端上下文中直接访问当前用户。提示Wasp 还支持 Google、GitHub、Email 等更多认证方式各方式在 auth 目录下都有对应文档并支持在同一个应用中同时启用多种方式。本篇聚焦最基础的用户名 密码。第三步添加登录与注册页面表单由 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 }TypeScript 版本的声明与上面完全一致src/...引用相同的组件路径。然后在src下编写刚才导入的两个 React 组件。登录页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 dont have an account yet (Link to/signupgo to signup/Link). /span /div ) }注册页与登录页结构几乎相同只是换成SignupFormimport { 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/logingo to login/Link). /span /div ) }LoginForm与SignupForm均从wasp/client/auth导入这是 Wasp 根据你的认证配置自动生成并暴露的客户端 API。仓库中 TodoAppTs 示例的 LoginPage.tsx 与 SignupPage.tsx 与上述代码一一对应。TypeScript 提示使用 TS 时可以借助 Wasp 的类型安全Link组件与routes对象编译期即可校验路由拼写错误。更多细节见 type-safe links 文档。第四步让主页要求登录未登录用户访问主页没有任何意义他们无法创建任务因此把主页设为私有页面// ... page MainPage { authRequired: true, component: import { MainPage } from src/MainPage }authRequired: true之后未认证用户访问/会被自动重定向到/login——这正是第二步中app.auth.onAuthFailedRedirectTo配置的作用。同时当页面标记了authRequired其 React 组件会通过 props 收到一个user对象import { AuthUser } from wasp/auth export const MainPage ({ user }: { user: AuthUser }) { // Do something with the user // ... }现在可以实际测试了访问应用主页/会被重定向到/login注册一个新账号后会被送回主页并看到任务列表。查看数据库中发生了什么启动 Prisma Studio 检查数据库wasp db studio你会看到数据库中除了Task实体外现在多出了User实体以及 Wasp 自动创建的一些额外 Prisma 模型如Auth、AuthIdentity、Session——这些模型承载着密码哈希等敏感认证数据由 Wasp 全权管理你不需要也不应该直接操作它们。不过此时如果你用不同用户登录并创建任务会发现所有用户共享同一份任务列表——因为 Query 和 Action 还没有按用户过滤数据。这就是下一步要解决的问题。第五步定义 User 与 Task 的关联关系首先在 Prisma schema 中定义用户与任务之间的一对多关系// ... 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? }这里Task.user通过外键userId关联到User.idUser.tasks则是反向的列表字段。修改实体后照例需要迁移数据库wasp db migrate-dev注意这里把user和userId设为可选?是为了让数据库中已有的、尚未分配给任何用户的历史任务得以保留。这种做法在实际项目中并不推荐——它允许数据库出现不属于任何人的任务这种无意义状态。正规做法是编写数据迁移来妥善处理存量任务哪怕只是把它们全部删除。教程出于简洁考虑暂时保留了可选字段。仓库中 schema.prisma 的最终形态即包含上述User.tasks Task[]与Task.user/Task.userId关系。第六步改造 Query 与 Action实现数据隔离接下来修改 Query 与 Action一方面拒绝未认证用户的访问另一方面只对当前登录用户的任务进行操作。查询getTasksimport { Task } from wasp/entities import { HttpError } from wasp/server import { GetTasks } from wasp/server/operations export const getTasks: GetTasksvoid, Task[] async (args, context) { if (!context.user) { throw new HttpError(401) } return context.entities.Task.findMany({ where: { user: { id: context.user.id } }, orderBy: { id: asc }, }) }关键点context.user由 Wasp 注入未登录时为null或undefined此时抛出HttpError(401)拒绝访问where: { user: { id: context.user.id } }通过关系过滤只返回属于当前用户的任务。操作createTask 与 updateTaskimport { Task } from wasp/entities import { HttpError } from wasp/server import { CreateTask, UpdateTask } from wasp/server/operations type CreateTaskPayload PickTask, description export const createTask: CreateTaskCreateTaskPayload, Task 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 } }, }, }) } type UpdateTaskPayload PickTask, id | isDone export const updateTask: UpdateTask UpdateTaskPayload, { count: number } async ({ id, isDone }, context) { if (!context.user) { throw new HttpError(401) } return context.entities.Task.updateMany({ where: { id, user: { id: context.user.id } }, data: { isDone }, }) }两个 Action 各自承担不同职责createTask用user: { connect: { id: context.user.id } }把新任务直接挂到当前用户名下updateTask在where中同时限定id与user: { id: context.user.id }确保只能修改自己的任务即使传入别人的任务 id 也无法命中。说明由于 Prisma 的update不允许在where中使用关系字段这里必须改用updateMany才能把用户 id 写进过滤条件。这是 Prisma 自身的约束Wasp 教程特意做了标注。仓库中 queries.ts 与 actions.ts 即是上述逻辑的完整落地版本HttpError统一从wasp/server导入。验证多用户隔离效果再次打开 Prisma Studiowasp db studio可以看到每个用户只拥有自己的任务数据隔离按预期生效。第七步添加登出按钮最后补上登出功能。在主页组件中导入并调用logout// ... import { logout } from wasp/client/auth //... const MainPage () { // ... return ( div // ... button onClick{logout}Logout/button /div ) }logout同样是wasp/client/auth导出的自动生成 API负责清理会话并跳转。仓库示例 MainPage.tsx 中可以看到完整的用法通过useQuery(getTasks)拉取当前用户任务并在按钮上直接绑定logout。关于 TS Spec 写法当前仓库的声明方式教程基于 0.16 版本的.wasp声明语法。当前仓库中的 TodoAppTs 示例已升级到基于wasp.sh/spec的 TypeScript spec 写法examples/tutorials/TodoAppTs/main.wasp.ts认证配置与路由声明等价如下export default app({ name: TodoApp, wasp: { version: 0.26.0 }, title: TodoApp, auth: { userEntity: User, methods: { usernameAndPassword: {}, }, onAuthFailedRedirectTo: /login, }, spec: [ route(RootRoute, /, page(MainPage, { authRequired: true })), route(SignupRoute, /signup, page(SignupPage)), route(LoginRoute, /login, page(LoginPage)), query(getTasks, { entities: [Task] }), action(createTask, { entities: [Task] }), action(updateTask, { entities: [Task] }), ], });可以看到auth配置块、authRequired: true、登录/注册路由一脉相承只是从.wasp文件搬进了 TypeScript 模块。两种写法表达的能力完全一致。总结与下一步至此TodoApp 拥有了一套完整可用的认证系统并且是真正的多用户应用用户可以注册、登录、登出只能看到和编辑自己的任务未认证访问会被重定向到登录页。完成认证之后可以继续探索更多特性用 Starter Templates 为下一个项目快速起步用 Web Sockets 把应用变成实时协作应用深入 认证概览 了解useAuth()、context.user的完整用法或参考 自定义认证 UI 用自有组件替换默认表单若要参与 Wasp 开发可参阅 贡献指南。【免费下载链接】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),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询