ARTICLE DETAIL

资讯详情

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

Wasp 如何创建自定义注册动作并加入额外验证与数据存储逻辑

Wasp 如何创建自定义注册动作并加入额外验证与数据存储逻辑 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/waspWasp 的默认注册流程是固定的启用email或usernameAndPassword认证方式后注册时只会保存账号与密码密码由 provider 自动哈希并跑默认的字段校验。如果你的需求超出了这个范围——比如注册时做额外的业务校验、在User实体上多存几个字段、或者在注册完成后调用自定义代码——就需要自己实现一个注册 action 来替代默认实现。官方文档Custom sign-up actions明确提示自定义注册动作复杂度较高任何小的疏漏都可能影响应用安全因此它只建议在确实必要时使用。先确认 auth hooks 和现有机制是否够用在动手写自定义注册动作之前先对照官方文档检查你的需求能否用更轻的机制满足auth overview、Auth hooks只需在注册前后插一段代码如封禁某些邮箱、注册后发欢迎邮件、同步到第三方服务用 auth hooks 的onBeforeSignup/onAfterSignup即可无需替换默认注册动作。hooks 声明在main.wasp.ts的auth字段里Wasp 会await异步 hookhook 抛出HttpError就能中止注册。只是想让注册表单多存几个字段如地址、姓名用auth.methods.{authMethod}.userSignupFields配合defineUserSignupFields即可无需自定义 action。注意字段名必须存在于schema.prisma的User实体上且password字段不在此列由 Wasp 的 auth 后端处理。必须完全接管注册逻辑自定义校验组合、条件化地拒绝或重发验证邮件等才走本文的自定义注册动作路径。还有一个硬限制要先知道使用自定义注册动作后不能再用 Wasp 生成的 Auth UISignupForm等组件。你需要自己实现注册界面并从界面代码中调用你创建的自定义动作。在 Wasp 文件中声明自定义注册动作以 email 认证为例修改main.wasp.ts引入两处内容auth.onBeforeSignup用来禁用默认注册动作和spec里的action(customSignup)注册你的自定义动作。import { action, app } from wasp.sh/spec import { onBeforeSignup } from ./src/auth/hooks with { type: ref } import { customSignup } from ./src/auth/signup with { type: ref } export default app({ name: myApp, wasp: { version: {latestWaspVersion} }, title: My App, head: [link relicon href/favicon.ico /], auth: { // ... onBeforeSignup, }, spec: [ action(customSignup), ], })说明{latestWaspVersion}是文档中的模板变量代表最新的 Wasp 版本。在已有项目里修改时保留你main.wasp.ts中已有的wasp: { version: ... }字段不动只需添加两个 import、auth.onBeforeSignup和spec中的action(customSignup)。Wasp 会按传入action(...)的函数名生成 action 名称即customSignup并同时在服务端和客户端生成同名的可调用函数客户端函数从wasp/client/operations导入参见 Actions 文档。禁用默认的注册动作在src/auth/hooks.ts中定义onBeforeSignup让它直接抛出HttpError从而阻止 Wasp 默认注册动作执行import { HttpError } from wasp/server // This disables Wasps default sign-up action export const onBeforeSignup async () { throw new HttpError(403, This sign-up method is disabled) }这一步是必做的它保证所有注册请求只走你的自定义动作不会落到默认流程上。实现自定义注册动作email 方式在src/auth/signup.ts中实现customSignup。文档给出的实现与 Wasp 内部默认注册的逻辑相似你可以在此基础上增删逻辑。完整起点如下import type { CustomSignup } from wasp/server/operations; import { HttpError } from wasp/server; import { createEmailVerificationLink, createProviderId, createUser, ensurePasswordIsPresent, ensureValidEmail, ensureValidPassword, findAuthIdentity, getProviderData, sanitizeAndSerializeProviderData, sendEmailVerificationEmail, } from wasp/server/auth; type CustomSignupInput { email: string; password: string; }; type CustomSignupOutput { success: boolean; message: string; }; export const customSignup: CustomSignup CustomSignupInput, CustomSignupOutput async (args, _context) { ensureValidEmail(args); ensurePasswordIsPresent(args); ensureValidPassword(args); try { const providerId createProviderId(email, args.email); const existingAuthIdentity await findAuthIdentity(providerId); let providerData; if (existingAuthIdentity) { // User already exists, handle accordingly // For example, throw an error or return a message throw new HttpError(400, Email already exists.); // Or, another example, you can check if the user is already // verified and re-send the verification email if not providerData getProviderDataemail( existingAuthIdentity.providerData, ); if (providerData.isEmailVerified) throw new HttpError(400, Email already verified.); } if (!providerData) { providerData await sanitizeAndSerializeProviderDataemail({ // The provider will hash the password for us, so we dont need to do it here. hashedPassword: args.password, isEmailVerified: false, emailVerificationSentAt: null, passwordResetSentAt: null, }); await createUser( providerId, providerData, // Any additional data you want to store on the User entity {}, ); } // Verification link links to a client route e.g. /email-verification const verificationLink await createEmailVerificationLink( args.email, /email-verification, ); try { await sendEmailVerificationEmail(args.email, { from: { name: My App Postman, email: helloitsme.com, }, to: args.email, subject: Verify your email, text: Click the link below to verify your email: ${verificationLink}, html: pClick the link below to verify your email/p a href${verificationLink}Verify email/a , }); } catch (e: unknown) { console.error(Failed to send email verification email:, e); throw new HttpError(500, Failed to send email verification email.); } } catch (e: any) { return { success: false, message: e.message, }; } // Your custom code after sign-up. // ... return { success: true, message: User created successfully, }; };这段代码里几个关键点决定了你的额外验证和额外数据存储写在哪里额外验证函数开头的ensureValidEmail、ensurePasswordIsPresent、ensureValidPassword是 Wasp 内置字段校验器从wasp/server/auth导入校验失败会抛错。官方建议自定义流程中也使用这些内置校验器——它们就是 Wasp 默认认证流程内部使用的同一套校验器。你自写的业务校验如检查邀请码、黑名单也放在函数开头或放进try块内按需抛HttpError。去重与条件分支findAuthIdentity(providerId)查到已有身份后文档示例给出两种处理方式——直接抛HttpError(400, Email already exists.)拒绝重复注册或者检查providerData.isEmailVerified并允许未验证用户重发验证邮件。你按产品需求二选一或改写。额外数据存储createUser(providerId, providerData, {...})的第三个参数就是“你想额外存到User实体上的数据”文档注释原文是Any additional data you want to store on the User entity。这里传入的字段名必须是你schema.prisma中User实体已定义的字段与userSignupFields的规则一致例如createUser(providerId, providerData, { address: args.address })。密码哈希把明文密码放进sanitizeAndSerializeProviderData的hashedPassword字段即可注释明确说明 “The provider will hash the password for us”——provider 会自动哈希你不需要自己处理哈希也不要把密码当明文存进User实体。返回值约定try块内所有异常都被兜底捕获统一返回{ success: false, message }正常走完则返回{ success: true, message: User created successfully }。客户端据此渲染结果。try之后还有 “Your custom code after sign-up” 的位置可放注册成功后的自定义逻辑。验证邮件部分createEmailVerificationLink(args.email, /email-verification)生成的链接指向客户端路由sendEmailVerificationEmail负责发送。邮件正文的from发件人信息示例中为My App Postman/helloitsme.com按你的发件配置替换。客户端实现自己的注册页面由于自定义注册动作不能搭配 Wasp 生成的 Auth UI你需要自己写注册页面并调用customSignup。按 Email Create your own UI 中的页面模式改写即可核心差别是把对signup的调用替换为对customSignup的调用并处理它返回的{ success, message }import { customSignup } from wasp/client/operations import { useState } from react export function SignupPage() { const [email, setEmail] useState() const [password, setPassword] useState() const [error, setError] useStateError | null(null) const [success, setSuccess] useState(false) async function handleSubmit(event: React.SubmitEventHTMLFormElement) { event.preventDefault() setError(null) const result await customSignup({ email: email.trim(), password }) if (!result.success) { setError(new Error(result.message)) return } setSuccess(true) } if (success) { return pCheck your email for the confirmation link./p } return ( form onSubmit{handleSubmit} {error pError: {error.message}/p} input typetext inputModeemail autoCompleteemail value{email} onChange{(e) setEmail(e.target.value)} placeholderEmail / input typepassword value{password} onChange{(e) setPassword(e.target.value)} placeholderPassword / button typesubmitSign Up/button /form ) }两点注意email 输入框按文档要求使用typetext加inputModeemail与autoCompleteemail因为 Wasp 的合法 email 定义比 HTML5 语法更宽支持 Unicodetypeemail会拒绝国际化邮箱输入。注册成功后用户需要点击验证邮件里的链接完成邮箱验证——验证链接指向/email-verification路由该路由页面上按 Email Create your own UI 中的EmailVerificationPage模式调用wasp/client/auth的verifyEmail({ token })token 从 URL query 参数读取。校验规则与结果判断自定义动作不会自动获得 Wasp 的默认校验——文档明确说明 “If you decide to create your custom auth actions, youll need to run the validations yourself.” 内置校验器均从wasp/server/auth导入校验不通过即抛错ensureValidUsername(args)校验 username。ensureValidEmail(args)校验 email。ensurePasswordIsPresent(args)校验 password 非空。ensureValidPassword(args)校验 password 规则。对应的默认校验规则auth overviewemail 不能为空且必须是合法邮箱HTML5 格式放宽以支持 Unicodepassword 不能为空、至少 8 个字符、必须包含数字username 不能为空。email 和 username 均按大小写不敏感方式存储所以去重逻辑用findAuthIdentity即可覆盖大小写差异。验证你的实现是否按预期工作依据文档示例代码可对照以下行为合法输入完成注册action 返回{ success: true, message: User created successfully }文档示例输出用户收到指向/email-verification的验证邮件邮箱已被占用且未验证按示例抛HttpError(400, Email already exists.)客户端收到success: false与对应 message已验证邮箱重复注册示例抛HttpError(400, Email already verified.)直接调用被禁用的默认注册入口收到HttpError(403, This sign-up method is disabled)这反过来说明onBeforeSignup拦截已生效。以上 message 与状态码来自文档示例代码如果你的业务逻辑改写了对应分支实际返回以你实现的分支为准。限制与替代路径安全性官方以 danger 级别提示自定义注册动作复杂且 “any small mistake will compromise the security of your app”。写完后重点检查密码是否始终通过sanitizeAndSerializeProviderData的hashedPassword路径存储、重复身份分支是否有绕过、异常是否会被静默吞掉。不能用 Wasp UI生成组件SignupForm等与自定义注册动作不兼容注册界面必须自实现登录界面是否继续用 Wasp UI文档未限制可按需混用。username password 方式文档给出了同构的customSignup变体——校验器换成ensureValidUsernameproviderId 用createProviderId(username, args.username)且没有邮箱验证环节。结构与 email 版本一致按需替换即可。需求降级路径如果后续发现你的需求其实只是注册前后跑一段代码或只是多存几个表单字段可以回退到 auth hooks 或 userSignupFields 方案删掉自定义动作并移除onBeforeSignup中的拦截逻辑。【免费下载链接】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),仅供参考
返回列表