Open SaaS 认证体系实战:在 Wasp 中配置 Email、Google、GitHub 与 Discord 登录 Open SaaS 认证体系实战在 Wasp 中配置 Email、Google、GitHub 与 Discord 登录【免费下载链接】open-saasA 100% free modern JS SaaS boilerplate (React, NodeJS, Prisma). Full-featured: Auth (email, google, github, slack, MS), Email sending, Background jobs, Landing page, Payments (Stripe, Polar.sh), Shadcn UI, S3 file upload. AI-ready with tailored AGENTS.md, skills, and Claude Code plugin. One cmd deploy. Powered by Wasp full-stack framework.项目地址: https://gitcode.com/GitHub_Trending/op/open-saas本指南以 Open SaaS 模板的官方认证文档为核心结合仓库源码系统讲解如何在 main.wasp.ts 中声明式地配置认证方法完成邮箱验证、密码重置、第三方社交登录的接入并深入解析 Wasp 自动生成的认证实体、AuthUI 页面与自定义注册字段的实现细节。读完本文你将能够在 Open SaaS 项目中开箱即用地启用多方式登录并安全地将其切换到生产环境。认证配置入口main.wasp 中的声明式 AuthOpen SaaS 的认证能力由 Wasp 全栈框架提供而配置入口只有一个地方——应用的main.wasp文件。原文档给出了经典的声明式写法auth: { userEntity: User, methods: { email: {}, google: {}, gitHub: {}, discord: {} }, onAuthFailedRedirectTo: /, },在当前仓库中这一配置被拆分到了独立的模块中挂载main.wasp.ts通过import { authConfig, authSpec } from ./src/auth/auth.wasp引入并在app({ ..., auth: authConfig, ... })中装配同时把authSpec追加进spec路由列表见 main.wasp.ts。真正生效的认证配置位于 src/auth/auth.wasp.ts其完整形态比文档示例更丰富export const authConfig: Auth { userEntity: User, methods: { email: emailAuthMethod, // usernameAndPassword: usernameAndPasswordAuthMethod, // google: googleAuthMethod, // gitHub: gitGubAuthMethod, // discord: discordAuthMethod, }, onAuthFailedRedirectTo: /login, onAuthSucceededRedirectTo: /demo-app, };从源码结构可以看到两个要点默认只启用了email认证Google、GitHub、Discord 以及可选的usernameAndPassword都以注释形式保留取消注释即可启用重定向策略更细化登录失败跳转/login登录成功跳转/demo-app演示 AI 应用页而模板早期的onAuthFailedRedirectTo: /被落地页所取代。声明式配置的核心价值在于你只需要描述要什么认证方式Wasp 会自动完成其余工作——包括为认证和会话创建对应的数据库实体、生成服务端接口以及按需生成登录/注册等客户端组件即 AuthUI。这些自动生成的组件可以直接在src/auth目录下使用。认证实体与会话User 模型与自动数据库表当你在auth.userEntity中声明User实体后Wasp 会围绕它自动维护凭据credentials与会话sessions相关的数据库表你无需手写迁移逻辑。Open SaaS 的 schema.prisma 中User模型本身还扩展了 SaaS 业务所需的字段model User { id String id default(uuid()) createdAt DateTime default(now()) email String? unique username String? unique isAdmin Boolean default(false) paymentProcessorUserId String? unique subscriptionStatus String? // active, cancel_at_period_end, past_due, deleted subscriptionPlan String? // hobby, pro datePaid DateTime? credits Int default(3) gptResponses GptResponse[] contactFormMessages ContactFormMessage[] tasks Task[] files File[] }值得注意的细节email与username均允许为空但唯一这是为了兼容社交登录场景——GitHub/Discord 用户可能没有公开邮箱此时可以只存 usernameisAdmin字段配合ADMIN_EMAILS环境变量实现管理员判定下文展开subscriptionStatus、subscriptionPlan等支付相关字段使得认证与后续的授权如区分免费/付费用户天然衔接。关于这些权限字段的完整说明可参阅 user-overview.md。Email 认证邮箱验证与 Dummy 邮件发送器email方法是 Open SaaS 的默认认证方式在 auth.wasp.ts 中email: emailAuthMethod直接启用。由于它需要发送验证邮件和密码重置邮件因此依赖一个邮件发送器email sender服务通过app.emailSender字段配置。本地开发Dummy Provider为了让新用户零成本上手模板默认使用Dummy邮件发送器——它不会真正发送任何邮件而是把所有验证链接/令牌打印到服务端控制台日志中。你在本地注册后需要到运行wasp start的终端里找到形如Click the link below to verify your email的链接点击它才能完成邮箱验证、继续注册流程。Dummy的默认配置见 src/server/emailSender.wasp.tsexport const emailSender: EmailSender { provider: Dummy, defaultFrom: { name: Open SaaS App, email: meexample.com, }, };必须牢记Dummy仅限本地开发。正如原文档与 email-sending.mdx 双重强调的使用Dummy生产构建不会通过你必须切换到生产级发送商如 SendGrid、Mailgun应用才能正常构建。验证邮件与重置邮件的模板定制Wasp 会调用你在emailAuthMethod中指定的内容生成函数来产出验证/重置邮件定义在 src/auth/email-and-pass/emails.tsexport const getVerificationEmailContent: GetVerificationEmailContentFn ({ verificationLink, }) ({ 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 , }); export const getPasswordResetEmailContent: GetPasswordResetEmailContentFn ({ passwordResetLink, }) ({ subject: Password reset, text: Click the link below to reset your password: ${passwordResetLink}, html: pClick the link below to reset your password/p a href${passwordResetLink}Reset password/a , });这两个函数分别绑定在 auth.wasp.ts 的emailAuthMethod.emailVerification.getEmailContentFn与emailAuthMethod.passwordReset.getEmailContentFn上同时各自指定了客户端路由EmailVerificationRoute、PasswordResetRoute构成邮件发链接 → 前端页面收链接 → 回调完成验证/重置的完整闭环。如需自定义邮件文案或样式直接修改这两个函数即可。迁移到生产级邮件发送商SendGrid / Mailgun在原文档的步骤基础上结合仓库中的 email-sending.mdx完整的生产化迁移流程如下以 SendGrid 为例注册 SendGrid 账户在 SendGrid 后台生成 API Key将 API Key 写入.env.server文件变量名为SENDGRID_API_KEY修改main.wasp中的emailSender把provider由Dummy换成SendGrid并确保defaultFrom.email与你 SendGrid 账户中配置的发件邮箱完全一致不一致会导致邮件被拒发emailSender: { provider: SendGrid, defaultFrom: { name: Open SaaS App, // 必须与 SendGrid 账户配置的发件邮箱一致 email: meexample.com }, },若选用 Mailgun在.env.server中新增MAILGUN_API_KEY与MAILGUN_DOMAIN两个变量provider改为Mailgun其余步骤相同。切换完成后Wasp 会自动更新 AuthUI 组件。此后你便可以在服务端任意位置用emailSender.send({ to, subject, text, html })发送业务邮件例如 Stripe 订阅取消时的挽留邮件见 email-sending.mdx 中的 webhook 示例。Google、GitHub、Discord 社交登录接入原文档指出模板已为 Google、GitHub、Discord 三个社交登录预置了定制流程启用方式只有两步取消注释 配置 API Key。第一步取消注释认证方法在 src/auth/auth.wasp.ts 中三个方法都已定义好并挂好了对应的用户字段解析与 OAuth 配置函数const googleAuthMethod: NonNullableAuthMethods[google] { userSignupFields: getGoogleUserFields, configFn: getGoogleAuthConfig, }; const gitGubAuthMethod: NonNullableAuthMethods[gitHub] { userSignupFields: getGitHubUserFields, configFn: getGitHubAuthConfig, }; const discordAuthMethod: NonNullableAuthMethods[discord] { userSignupFields: getDiscordUserFields, configFn: getDiscordAuthConfig, };把它们逐个取消注释并加入authConfig.methods即可。注意注释中的提示email与usernameAndPassword是互斥的不能同时启用。第二步配置 OAuth 应用与密钥在对应 OAuth 提供商的开发者后台创建应用后把密钥写入.env.server。结合 userSignupFields.ts 中的configFn可以确认每个提供商实际请求的 OAuth scope认证方式请求的 scopes说明Googleprofile,email至少需要profile才能获取用户资料GitHubuser:email用于读取用户的邮箱列表Discordidentify,email用于获取 username 与邮箱例如 GitHub 的配置函数// NOTE: if we dont want to access users emails, we can use scope [user:read] // instead of [user] and access args.profile.username instead export function getGitHubAuthConfig() { return { scopes: [user:email], }; }源码中的注释提供了可选的降权方案若业务不需要用户邮箱可将 scope 收窄为user:read并改用profile.username减少权限暴露面。社交登录的用户数据解析defineUserSignupFields社交登录与邮箱登录的一大差异在于OAuth 返回的是原始 profile 数据你需要从中提取email、username并映射到User实体。模板在 userSignupFields.ts 中为每个提供商实现了这套映射并统一使用zod做运行时校验。以 Discord 为例它要求用户必须有关联邮箱因为 Open SaaS 的支付流程需要邮箱否则直接抛出可读错误export const getDiscordUserFields defineUserSignupFields({ email: (data) { const discordData discordDataSchema.parse(data); // Users need to have an email for payment processing. if (!discordData.profile.email) { throw new Error( You need to have an email address associated with your Discord account to sign up., ); } return discordData.profile.email; }, username: (data) { const discordData discordDataSchema.parse(data); return discordData.profile.username; }, isAdmin: (data) { const discordData discordDataSchema.parse(data); if (!discordData.profile.email || !discordData.profile.verified) { return false; } return isAdminEmail(discordData.profile.email); }, });GitHub 的实现则从profile.emails列表中取第一个邮箱并要求邮箱必须已验证verified才授予管理员身份Google 同样校验email_verified。这些逻辑统一复用底层的isAdminEmail()辅助函数。注册字段定制与管理员判定ADMIN_EMAILS无论使用哪种登录方式isAdmin字段的赋值都统一走isAdminEmail()function isAdminEmail(email: string): boolean { return env.ADMIN_EMAILS.includes(email); }ADMIN_EMAILS是模板内置的认证环境变量定义在 src/auth/env.tsexport const authEnvSchema z.object({ ADMIN_EMAILS: z .string() .default() .transform((val) val .split(,) .map((email) email.trim()) .filter(Boolean), ), });也就是说在.env.server中配置逗号分隔的邮箱列表如adminexample.com,opsexample.com对应邮箱注册的用户自动获得isAdmin: true。该 schema 通过 src/env.ts 的serverEnvValidationSchema合并进 Wasp 的服务端环境变量校验服务端代码用import { env } from wasp/server访问即可拿到已校验、已转换trim 后数组化的值。AuthUI自动生成的认证页面与路由Wasp 会根据认证配置动态生成客户端认证组件AuthUI模板在 src/auth 目录下直接复用了它们LoginPage.tsx渲染LoginForm /并提供跳转注册、找回密码的链接SignupPage.tsx渲染SignupForm /EmailVerificationPage.tsx渲染VerifyEmailForm /承接验证邮件中的链接另有PasswordResetPage、RequestPasswordResetPage处理密码重置流程。这些页面统一使用 AuthPageLayout.tsx 作为外壳并由 authSpec 注册了 5 条路由/login、/signup、/request-password-reset、/password-reset、/email-verification。页面中还使用了一个值得借鉴的小技巧——useRedirectIfLoggedInHook见 useRedirectIfLoggedIn.ts已登录用户访问登录/注册页时会自动被导航到/demo-app避免已登录却还能看到登录页的体验问题export function useRedirectIfLoggedIn(redirectTo /demo-app) { const { data: user } useAuth(); const navigate useNavigate(); useEffect(() { if (user) { navigate(redirectTo); } }, [user, navigate, redirectTo]); }这也解释了为什么onAuthSucceededRedirectTo与 Hook 默认值都指向/demo-app——它是注册成功后的默认落点。生产环境检查清单综合原文档与仓库源码将认证接入生产环境前请逐项确认邮件发送器emailSender.provider必须从Dummy切换为SendGrid或Mailgun等生产级提供商并在.env.server配置SENDGRID_API_KEY或MAILGUN_API_KEYMAILGUN_DOMAIN否则构建失败、验证/重置邮件无法送达发件人一致性defaultFrom.email必须与邮件服务商账户中授权的发件地址一致社交登录密钥Google/GitHub/Discord 的 OAuth 凭据Client ID/Secret写入.env.server并在提供方后台正确配置回调地址管理员邮箱通过ADMIN_EMAILS逗号分隔预置管理员注意 GitHub/Discord 用户只有在邮箱已验证的前提下才会被判定为管理员重定向体验确认onAuthFailedRedirectTo: /login与onAuthSucceededRedirectTo: /demo-app符合你的产品流程自定义注册字段如需在注册时收集额外信息如头像、公司名在userSignupFields.ts对应提供商的defineUserSignupFields中扩展字段Wasp 会将其同步进User实体。完成上述配置后Wasp 会接管认证的数据库实体、服务端校验与 AuthUI 更新你无需手写任何会话管理或密码哈希逻辑。更细粒度的访问控制如按订阅状态、管理员权限区分页面与接口属于授权Authorization范畴可继续阅读 authorization.md 与 user-overview.md 深入了解。【免费下载链接】open-saasA 100% free modern JS SaaS boilerplate (React, NodeJS, Prisma). Full-featured: Auth (email, google, github, slack, MS), Email sending, Background jobs, Landing page, Payments (Stripe, Polar.sh), Shadcn UI, S3 file upload. AI-ready with tailored AGENTS.md, skills, and Claude Code plugin. One cmd deploy. Powered by Wasp full-stack framework.项目地址: https://gitcode.com/GitHub_Trending/op/open-saas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考