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/wasp用户名与密码Username Password是 Wasp 内置的认证方式之一开箱即用无需自己实现密码哈希、会话管理或登录注册表单。本文以 Wasp 0.19 版本文档为骨架完整讲解如何在main.wasp中启用该认证、定义User实体、声明路由并用LoginForm/SignupForm组件搭建登录注册页面同时深入仓库源码还原登录/注册的服务端处理链路、密码校验规则、认证数据模型与userSignupFields扩展机制。读完本文你将能独立为一个 Wasp 应用接入完整的用户名密码认证并理解其底层原理。认证总览Wasp 提供的开箱即用能力Wasp 对用户名密码认证的支持包括两部分服务端实现登录、注册的处理逻辑由 Wasp 在生成代码时自动注入开发者不需要手写校验密码、创建会话等胶水代码客户端 UI 组件Wasp 在构建时生成LoginForm、SignupForm等 React 组件可直接在页面中引用。从 Wasp 0.19 的官方文档username-and-pass.md可以看出完整搭建只包含四个步骤在 Wasp 文件中启用用户名认证添加User实体添加认证相关的路由和页面在页面中使用 Auth UI 组件。最终main.wasp文件的结构如下// Configuring e-mail authentication app myApp { auth: { ... } } // Defining routes and pages route SignupRoute { ... } page SignupPage { ... } // ...第一步在 main.wasp 中启用用户名认证在main.wasp的app声明中添加auth配置块指定用户实体并启用usernameAndPassword认证方法app myApp { wasp: { version: {latestWaspVersion} }, title: My App, auth: { // 1. Specify the user entity (well define it next) userEntity: User, methods: { // 2. Enable username authentication usernameAndPassword: {}, }, onAuthFailedRedirectTo: /login } }其中userEntity: User指定承载业务用户数据的 Prisma 实体即下一步要定义的Usermethods: { usernameAndPassword: {} }声明启用用户名密码认证方式usernameAndPassword字典的完整字段会在后文「API 参考」中展开onAuthFailedRedirectTo: /login表示认证失败时的重定向目标。第二步添加 User 实体User实体可以简单到只包含一个id字段其余业务字段按需自行添加// 3. Define the user entity model User { // highlight-next-line id Int id default(autoincrement()) // Add your own fields below // ... }从 Wasp 注入的认证数据模型看User会被 Wasp 自动关联上Auth、AuthIdentity、Session等内部实体详见访问用户数据文档因此你只需要聚焦于业务字段本身。第三步添加认证路由与页面在main.wasp中声明登录与注册的路由和页面二者都指向src/pages/auth目录下导出的 React 组件// ... route LoginRoute { path: /login, to: LoginPage } page LoginPage { component: import { Login } from src/pages/auth } route SignupRoute { path: /signup, to: SignupPage } page SignupPage { component: import { Signup } from src/pages/auth }路由路径、页面组件名可根据实际需求调整但保持/login、/signup与onAuthFailedRedirectTo指向一致会让体验更顺畅。第四步使用 Auth UI 组件编写客户端页面在src/pages下创建auth.jsx或auth.tsx从wasp/client/auth导入生成的LoginForm和SignupForm组件再配合react-router-dom的Link做页面间跳转import { LoginForm, SignupForm } from wasp/client/auth import { Link } from react-router-dom export function Login() { return ( Layout LoginForm / br / span classNametext-sm font-medium text-gray-900 Dont have an account yet? Link to/signupgo to signup/Link. /span /Layout ) } export function Signup() { return ( Layout SignupForm / br / span classNametext-sm font-medium text-gray-900 I already have an account (Link to/logingo to login/Link). /span /Layout ) } // A layout component to center the content export function Layout({ children }: { children: React.ReactNode }) { return ( div classNameh-full w-full bg-white div classNameflex min-h-[75vh] min-w-full items-center justify-center div classNameh-full w-full max-w-sm bg-white p-5 div{children}/div /div /div /div ) }这里LoginForm/SignupForm就是 Wasp 在生成阶段产出的表单组件它们内部封装了用户名、密码输入框、校验逻辑与提交处理示例中用 Tailwind CSS 做样式美化。关于 Auth UI 组件的完整说明可参考认证 UI 文档。运行与验证完成上述四步后在项目根目录依次执行wasp db migrate-dev wasp startwasp db migrate-dev会创建/更新数据库包括 Wasp 注入的认证相关表wasp start启动开发服务器。此时访问/signup即可注册、访问/login即可登录。如果想将某些页面放到登录之后可通过页面的authRequired特性实现详见认证总览文档。服务端实现剖析登录与注册的处理链路启用认证后Wasp 生成的代码中会为用户名认证挂载两条 POST 路由/auth/username/login与/auth/username/signup。路由注册位于生成模板 config/username.tsrouter.post(/login, login); const signupRoute getSignupRoute({ userSignupFields: _waspUserSignupFields, }); router.post(/signup, signupRoute);登录流程登录处理器位于 login.ts其核心步骤是从请求体取出username与password先做参数合法性校验通过createProviderId(username, fields.username)构造 provider ID即「provider 名 provider 侧用户 ID」的组合用于唯一定位身份用findAuthIdentity(providerId)查询AuthIdentity找不到即抛出createInvalidCredentialsError()——统一返回「凭据无效」避免泄露用户名是否存在取回providerData中的hashedPassword调用verifyPassword校验明文密码校验失败同样抛出统一的无效凭据错误通过findAuthWithUserBy拿到关联的Auth与业务用户触发onBeforeLoginHook/onAfterLoginHook钩子调用createSession(auth.id)创建会话并返回sessionId客户端随后用该 ID 初始化登录态。注册流程注册处理器位于 signup.ts流程为ensureValidArgs校验用户名、密码是否存在且合法构造 provider ID先执行onBeforeSignupHook——钩子可以提前抛出异常来否决本次注册调用validateAndGetUserFields运行开发者定义的userSignupFieldsgetter收集需要写入User的额外字段sanitizeAndSerializeProviderData负责对密码做哈希hashedPassword字段并序列化为 JSON 字符串存入providerDatacreateUser创建Auth、AuthIdentity与User记录成功后触发onAfterSignupHook。密码与用户名校验规则参数校验实现在 validation.ts这是用户名密码认证的硬性约束注册与登录共用username必须存在ensureValidUsernamepassword必须存在ensurePasswordIsPresent密码长度至少 8 个字符且必须包含数字ensureValidPassword中的isMinLength(password, 8)与containsNumber。任何一条不满足都会抛出 422Validation failed错误并附带对应的message如password must be at least 8 characters、password must contain a number。客户端 APIlogin 与 signup生成在客户端 SDK 中的调用入口位于 client/auth/username.ts对外只导出login与signup两个函数login(data: { username, password })实现见 actions/login.ts向{loginPath}发起 POST 请求拿到sessionId后调用initSession(sessionId)写入会话使后续请求自动携带登录态signup(data: UsernameSignupData)实现见 actions/signup.ts向{signupPath}发起注册请求其中UsernameSignupData除了username、password外若你在main.wasp中配置了userSignupFields还会包含对应的扩展字段类型。表单组件的提交逻辑见 useUsernameAndPassword.ts注册场景先调用signup(data)再调用login(data)注册成功后自动完成登录登录场景则只调用login随后触发onSuccess回调。这些钩子最终被 LoginSignupForm.tsx 中的通用登录/注册表单组件消费LoginForm/SignupForm即由此生成。使用认证获取当前用户、登出与保护页面认证不只是登录注册日常开发更常需要的是「当前是谁登录了」以及「登出」。这两点由认证总览文档统一说明详见 overview.md这里给出关键用法保护页面authRequired——在main.wasp的page声明中设置authRequired: true未登录用户会被重定向页面组件还会直接收到userproppage AccountPage { component: import Account from src/pages/Account, authRequired: true }import type { AuthUser } from wasp/auth import { logout } from wasp/client/auth const AccountPage ({ user }: { user: AuthUser }) { return ( div button onClick{logout}Logout/button {JSON.stringify(user, null, 2)} /div ) }未受保护页面用useAuth钩子——useAuth是useQuery的薄封装返回数据格式一致适合在任意组件中判断登录态import { useAuth, logout } from wasp/client/auth import { Link } from react-router-dom export function Main() { const { data: user } useAuth() if (!user) { return ( span Please Link to/loginlogin/Link or{ } Link to/signupsign up/Link. /span ) } else { return ( button onClick{logout}Logout/button / ) } }登出——logout函数同样从wasp/client/auth导入点击按钮即可销毁会话。访问用户的用户名无论通过useAuth、页面userprop 还是服务端context.user拿到user对象其认证相关字段都存放在identities下。对用户名认证而言通过identities.username即可访问const usernameIdentity user.identities.username // Username that the user used to sign up, e.g. fluffyllama usernameIdentity.id完整的AuthUser对象结构、多认证方式下的判空写法以及getFirstProviderUserId辅助方法可参考访问用户数据文档。需要注意未使用某认证方式时对应identities下的数据为null访问前应先判空。扩展userSignupFields 自定义注册字段如果你的User实体需要额外字段如address、phone可以在usernameAndPassword字典中通过userSignupFields指定一个导入的配置函数app myApp { wasp: { version: {latestWaspVersion} }, title: My App, auth: { userEntity: User, methods: { usernameAndPassword: { userSignupFields: import { userSignupFields } from src/auth/email, }, }, onAuthFailedRedirectTo: /login } } // ...在src/auth.ts中使用 Wasp 提供的defineUserSignupFields定义每个字段如何从注册表单数据中取值。getter 可以自行校验不满足时抛出错误拒绝注册也可以直接返回原始值import { defineUserSignupFields } from wasp/server/auth export const userSignupFields defineUserSignupFields({ address: (data) { if (!data.address) { throw new Error(Address is required) } return data.address }, phone: (data) data.phone, })结合上文注册流程的源码可以看到这些 getter 会在服务端validateAndGetUserFields阶段被依次执行返回值作为createUser的额外数据写入User记录。关于注册流程定制如onBeforeSignupHook/onAfterSignupHook与签名字段的更多细节可参考认证总览中的注册定制章节以及 auth-hooks.md。API 参考userEntity 字段与 usernameAndPassword 配置userEntity字段要求userEntity指向的 Prisma 模型必须包含以下字段id必填可以是任意类型但必须标注id。其余字段可任意添加如果这些字段需要在注册阶段由用户填写则必须同时在userSignupFields中定义对应的 getter见上文示例。usernameAndPassword字典的字段字段类型说明userSignupFieldsExtImport定义注册过程中需要写入User的额外字段及其取值/校验逻辑通过import { userSignupFields } from ...引入认证数据模型Auth、AuthIdentity 与 SessionWasp 在数据库层通过三个内部实体支撑用户名密码认证理解它们有助于排查问题或编写自定义注册逻辑模型定义见访问用户数据文档Auth连接业务用户User与登录凭据的枢纽。id为 UUID 主键userId外键指向User并级联关联identities与sessions。AuthIdentity按 provider 维度存储登录凭据。providerName为 provider 名用户名认证下为usernameproviderUserId为 provider 侧的用户 ID用户名认证下就是注册时的用户名二者联合组成主键id([providerName, providerUserId])providerData是 JSON 字符串密码类认证的哈希密码hashedPassword就存在这里。使用String而非 PrismaJson类型是为了兼容 SQLite。Session存储会话expiresAt记录过期时间用于在页面刷新后保持登录。多身份限制说明Wasp 目前不支持一个用户拥有多个认证身份。例如同一个用户不能同时拥有基于用户名的身份和基于 Google 的身份。这一限制意味着user.identities中只会有一个 provider 的数据非空。官方计划在未来通过「账户合并account merging」功能支持把多个身份合并到同一个账户届时用户既可以用邮箱登录也可以用 Google 登录同一个账号。详见多身份警告。小结用户名密码认证是 Wasp 中门槛最低的认证方案声明式配置usernameAndPassword 一个User实体 两个路由 两个生成组件即可获得完整的注册、登录、会话、登出能力。其背后Wasp 在代码生成阶段注入了经过校验的登录/注册处理器、密码哈希存储AuthIdentity.providerData与会话机制同时保留userSignupFields和认证钩子用于业务定制。若需要将页面置于登录之后、或获取当前登录用户在客户端与服务端的引用请继续阅读认证总览文档与访问用户数据文档它们与本文共同构成完整的 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),仅供参考
返回列表