Wasp 中通过 getEmail 获取用户邮箱:从wasp/auth帮助函数到 AuthIdentity 底层实现
【免费下载链接】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
getEmail是 Wasp 提供的认证辅助函数,用于从登录用户对象中安全地取出邮箱地址(对应邮箱认证身份),并在用户没有邮箱认证身份时返回null。本指南以 Wasp 0.12 文档为骨架,结合仓库中 SDK 模板源码与 kitchen-sink 示例,讲解getEmail在前端页面(userprop)与后端操作(context.user)中的完整用法,并深入剖析其背后的AuthIdentity数据模型与实现原理,帮助你在实际项目中正确读取、判空并展示用户邮箱。
getEmail 是什么
在 Wasp 中,当应用启用了邮箱认证(email auth)后,凡是你拿到的user对象都包含auth字段,其中存放着与该用户关联的认证身份(auth identities)。邮箱本身并不直接挂在user上,而是存储在认证身份数组user.auth.identities里。
为了让读取邮箱的过程更简单、更不易出错,Wasp 在 SDK 中提供了getEmail帮助函数,其行为如下:
- 有邮箱认证身份时:返回该用户的邮箱字符串;
- 没有邮箱认证身份时(例如仅使用 Google、GitHub 等社交登录,或尚未绑定邮箱):返回
null。
该函数通过import { getEmail } from 'wasp/auth'引入,在前端和服务端代码中均可使用,且返回值类型统一为string | null,方便你统一做空值兜底处理。
在前端页面获取邮箱(userprop)
在 Wasp 的页面声明中,如果将authRequired设置为true,对应的 React 组件就会收到user对象 prop。此时可以直接把user传给getEmail取出邮箱:
import { getEmail } from 'wasp/auth' const MainPage = ({ user }) => { const email = getEmail(user) // ... }对应的 TypeScript 版本需要显式标注user的类型为AuthUser(同样从wasp/auth导入):
import { getEmail, AuthUser } from 'wasp/auth' const MainPage = ({ user }: { user: AuthUser }) => { const email = getEmail(user) // ... }由于getEmail可能返回null,在渲染到界面时建议配合兜底文案,例如仓库中 kitchen-sink 示例 ListPage.tsx 的做法:
<p className="mt-1 text-sm text-gray-500">import { getEmail } from 'wasp/auth' export const createTask = async (args, context) => { const email = getEmail(context.user) // ... }TypeScript 版本的 action 定义如下(泛型参数CreateTask<...>由 Wasp 依据main.wasp中的声明自动生成并校验输入输出类型):
import { getEmail } from 'wasp/auth' export const createTask: CreateTask<...> = async (args, context) => { const email = getEmail(context.user) // ... }注意:context.user中包含User实体的全部字段以及与之关联的认证身份信息;出于安全考虑,Wasp 会从身份数据中剥离hashedPassword字段(详见 auth/overview.md),因此通过getEmail读取邮箱不会暴露任何密码相关数据。
为什么返回null:邮箱身份与多身份模型
getEmail返回null的语义源自 Wasp 内部的三张认证实体(详见 auth/entities/entities.md):
Auth:连接业务用户User与登录凭据的中间实体;AuthIdentity:存放具体某种认证方式的凭据,其中providerName是提供方名称(如email、google),providerUserId是用户在提供方侧的 ID——对邮箱认证而言,providerUserId就是邮箱地址本身;Session:保存会话信息。
其 Prisma 结构如下:
entity AuthIdentity {=psl providerName String providerUserId String providerData String @default("{}") authId String auth Auth @relation(fields: [authId], references: [id], onDelete: Cascade) @@id([providerName, providerUserId]) psl=}因此,Wasp 中“用户的邮箱”本质上是user.auth.identities数组中providerName === "email"那条身份记录的providerUserId。如果数组里不存在邮箱身份(比如该用户是用社交账号登录的),getEmail自然返回null。0.12 版本还不支持单个用户同时拥有多种认证身份(见 _multiple-identities-warning.md),所以对大多数用户而言邮箱身份要么存在、要么不存在,判断逻辑是清晰且确定的。
user对象的实际形态可以参考 auth/overview.md 中的示例:
const user = { id: "19c7d164-b5cb-4dde-a0cc-0daea77cf854", // Your entity's fields. address: "My address", // ... // Auth identities connected to the user. auth: { id: "26ab6f96-ed76-4ee5-9ac3-2fd0bf19711f", identities: [ { providerName: "email", providerUserId: "some@email.com", providerData: { ... }, }, ] }, }底层实现:从 SDK 源码看 getEmail 的调用链
在仓库的 SDK 生成模板 wasp/auth/user.ts 中,getEmail的实现非常精简:
// PUBLIC API export function getEmail(user: UserEntityWithAuth): string | null { return findUserIdentity(user, "email")?.providerUserId ?? null; }其核心逻辑落在findUserIdentity(user.ts):先检查user.auth是否存在,再从user.auth.identities数组中按providerName找到对应身份记录,取回providerUserId;找不到或auth为null时整体返回null:
function findUserIdentity(user: UserEntityWithAuth, providerName: ProviderName): NonNullable<UserEntityWithAuth['auth']>['identities'][number] | null { if (!user.auth) { return null; } return user.auth.identities.find( (identity) => identity.providerName === providerName ) ?? null; }也就是说,getEmail(user)等价于user.auth?.identities.find(i => i.providerName === "email")?.providerUserId ?? null,SDK 只是把它封装成了可读性更好、类型更安全的函数。
这些辅助函数统一从 wasp/auth/index.ts 导出,构成wasp/auth模块的公共 API:
// PUBLIC API export { getEmail, getUsername, getFirstProviderUserId, } from './user.js' // PUBLIC API export type { AuthUser } from './user.js'与 getEmail 同源的配套 API
同文件 user.ts 中还定义了另外两个常用的公共函数和AuthUser类型,适合在需要处理多种认证身份时搭配使用:
getUsername(user):返回用户名认证身份对应的providerUserId(即用户名),没有该身份时返回null,实现逻辑与getEmail完全对称;getFirstProviderUserId(user?):返回用户第一条认证身份的providerUserId,适用于不关心具体提供方、只想拿一个稳定的用户标识的场景;无身份时返回null;AuthUser:SDK 暴露给客户端/服务端的用户类型,由AuthUserData与getFirstProviderUserId方法组合而成,TypeScript 用户在前端标注userprop 类型时直接使用它即可(如本文第二节的 TS 示例)。
实战要点小结
- 统一入口:读取邮箱一律走
import { getEmail } from 'wasp/auth',不要手动遍历user.auth.identities; - 必须判空:返回值类型是
string | null,用于展示时用??提供兜底文案,用于业务逻辑时先做空值判断; - 前后端通用:前端用
userprop(页面声明authRequired: true),服务端用context.user,两种场景下getEmail的调用方式一致; - 理解数据来源:邮箱即
AuthIdentity中providerName === "email"记录的providerUserId,理解这一点有助于排查"为什么返回了null"之类的疑问。
更多背景可继续阅读 auth/overview.md(认证整体概览与user对象)、auth/email.md(邮箱认证完整配置与 API 参考)以及 auth/entities/entities.md(Auth、AuthIdentity、Session实体详解)。
【免费下载链接】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),仅供参考