Hanko Frontend SDK 完整指南:浏览器端认证集成与 FlowAPI 自定义前端开发
发布时间:2026/10/2 1:37:22来源:尧图网络
后端认证鉴权前端【免费下载链接】hankoModern authentication, on your terms. Open source alternative to Auth0, Clerk, WorkOS, Stytch.项目地址https://gitcode.com/GitHub_Trending/ha/hanko点击查看免费下载teamhanko/hanko-frontend-sdk是 Hanko 官方提供、专为浏览器环境设计的 TypeScript 客户端库它封装了 Hanko API 的会话管理、用户信息拉取与事件通知能力并提供基于状态机模型的 FlowAPI让开发者可以不依赖现成 UI 组件、自由构建自定义登录与个人资料前端。读完本文你将掌握 SDK 的安装接入、实例选项、会话生命周期事件监听、会话/用户管理方法以及从零驱动 FlowAPI 完成认证流程含自动步进、Passkey 自动填充、状态缓存与错误处理的完整实战方案。安装SDK 以 npm 包形式发布包名为teamhanko/hanko-frontend-sdk当前仓库版本为 3.0.0见 frontend/frontend-sdk/package.json支持主流的包管理器# npm npm install teamhanko/hanko-frontend-sdk # yarn yarn add teamhanko/hanko-frontend-sdk # pnpm pnpm install teamhanko/hanko-frontend-sdk该包仅面向浏览器运行package.json 中明确注明 It is meant for use in browsers only其产物支持多种模块格式dist/sdk.cjsCommonJS、dist/sdk.modern.jsESM以及dist/sdk.umd.jsUMD分别通过exports、module与unpkg字段对外暴露。快速接入模块导入与 CDN 两种方式作为 ES 模块导入import { Hanko } from teamhanko/hanko-frontend-sdk const hanko new Hanko(http://localhost:3000)构造函数第一个参数是 Hanko API 实例的地址即 backend 服务的 URL。通过 CDN 的 script 标签使用script srchttps://cdn.jsdelivr.net/npm/teamhanko/hanko-frontend-sdk/dist/sdk.umd.js/script script const hanko new hankoFrontendSdk.Hanko(http://localhost:3000) ... /scriptUMD 构建会把全部导出挂载到全局命名空间hankoFrontendSdk下适合无构建工具的场景。SDK 的入口文件 frontend/frontend-sdk/src/index.ts 集中导出了Hanko主类、各子客户端HttpClient、SessionClient、UserClient、Relay、WebAuthn 工具函数、DTO 类型Email、Identity、SessionCheckResponse、Claims、全部错误类型以及 FlowAPI 相关的类型。实例选项Options创建Hanko实例时可以传入第二个可选参数来定制行为。以下默认值直接对应 Hanko.ts 构造函数中的实现const defaultOptions { timeout: 13000, // The timeout (in ms) for the HTTP requests. cookieName: hanko, // The cookie name under which the session token is set. localStorageKey: hanko, // The prefix / name of the localStorage keys. sessionCheckInterval: 30000, // Interval (in ms) for session validity checks. Must be greater than 3000 (3s). sessionCheckChannelName: hanko-session-check // The broadcast channel name for inter-tab communication }; const hanko new Hanko(http://localhost:3000, defaultOptions);在源码的HankoOptions接口frontend/frontend-sdk/src/Hanko.ts中还定义了 README 之外的可选字段可供深度定制选项类型默认值说明timeoutnumber13000HTTP 请求超时时间毫秒cookieNamestringhankoSDK 写入会话 token 的 cookie 名cookieDomainstring当前页面域名cookie 生效的域名cookieSameSiteCookieSameSitelax跨站请求时 cookie 的发送策略localStorageKeystringhankolocalStorage 键名前缀langstring—向 API 传递的首选语言见下文邮件翻译sessionCheckIntervalnumber30000会话有效性轮询间隔毫秒必须大于 3000否则强制设为 3000sessionCheckChannelNamestringhanko-session-check跨标签页通信的 BroadcastChannel 名称sessionTokenLocationcookie \| sessionStorage—会话 token 的存储位置其中sessionCheckInterval的最小值约束在 Relay.ts 中实现若传入值小于 3000 会被直接钳制为 3000。而sessionCheckChannelName在sessionTokenLocation为sessionStorage时会以该值为前缀生成随机通道名并持久化到sessionStorage用于区分不同标签页间的会话同步见 Relay.ts。会话事件Session EventsSDK 基于浏览器原生CustomEvent派发自定义事件。Hanko继承自Listener基类frontend/frontend-sdk/src/lib/events/Listener.ts所有onXxx方法都返回一个CleanupFunc移除函数调用它即可注销监听器。事件绑定通用模式如下// Controls the optional once parameter. When set to true the callback function will be called only once. const once false; const removeEventListener hanko.onSessionCreated((eventDetail) { // Your code... }, once);hanko-session-created在会话创建、且用户完成所有附加步骤如 passkey 注册或密码恢复后触发当用户在其他浏览器窗口登录时当前窗口也会触发。该事件可用于获取 JWT 的 claimshanko.onSessionCreated((sessionDetail) { // A new JWT has been issued. console.info(Session created, sessionDetail.claims); })从源码看SessionDetail包含claimsJWT 声明对象与已废弃的expirationSeconds字段frontend/frontend-sdk/src/lib/events/CustomEvents.ts。该事件在success状态的 auto-step 中被派发SDK 从成功载荷中取出 claims计算剩余有效期后调用dispatchSessionCreatedEventfrontend/frontend-sdk/src/lib/flow-api/auto-steps.ts并同时通过 BroadcastChannel 广播给其他标签页。hanko-session-expired会话过期、或用户在另一个窗口登出/删除账号导致会话被移除时触发hanko.onSessionExpired(() { // You can redirect the user to a login page or show the hanko-auth element, or to prompt the user to log in again. console.info(Session expired); })hanko-user-logged-out用户主动登出时触发。同一时刻其他浏览器窗口会触发hanko-session-expiredhanko.onUserLoggedOut(() { // You can redirect the user to a login page or show the hanko-auth element. console.info(User logged out); })hanko-user-deleted用户删除账号时触发。其他浏览器窗口同样会同步触发hanko-session-expiredhanko.onUserDeleted(() { // You can redirect the user to a login page or show the hanko-auth element. console.info(User has been deleted); })userDeleted事件由account_deleted状态的 auto-step 派发frontend/frontend-sdk/src/lib/flow-api/auto-steps.ts。事件名称常量集中在 frontend/frontend-sdk/src/lib/events/CustomEvents.ts 中定义。此外onSessionCreated与onSessionExpired在 Listener.ts 中默认开启了节流throttle默认 1 秒防止多个 SDK 实例同时触发同一事件时回调被重复执行。会话管理Session ManagementSDK 提供一组用于管理用户会话与获取用户信息的方法均由 Hanko.ts 中的Hanko类直接暴露。获取用户对象getCurrentUser拉取当前用户的完整资料返回值一个User对象包含user_id用户的唯一字符串标识passkeys已注册 passkey 数组WebauthnCredential[]可选security_keys已注册安全密钥数组WebauthnCredential[]可选mfa_configMFA 配置对象{ auth_app_set_up, totp_enabled, security_keys_enabled }可选emails邮箱对象数组如{ id: string, address: string, is_verified: boolean, is_primary: boolean, identities?: Identity[] }可选username用户名对象如{ id: string, username: string, created_at: string, updated_at: string }可选metadata自定义元数据对象{ public_metadata?, unsafe_metadata? }可选identities关联的第三方身份数组如{ id: string, provider: string, identity_id?: string }可选created_at/updated_atISO 8601 格式的创建与最后更新时间戳name、given_name、family_name、picture通过第三方提供商注册时填充的可选资料字段。错误UnauthorizedError会话无效或过期、TechnicalError服务端或网络问题。try { const user await hanko.getCurrentUser(); console.log(User profile:, user); // Example output: // { // user_id: 123e4567-e89b-12d3-a456-426614174000, // passkeys: [{ // id: d6df75e0-8a2b-4c6d-9b6e-1a2b3c4d5e6f, // name: MacBook Touch ID, // public_key: ..., // attestation_type: none, // aaguid: 08987058-cadc-4b81-b6e1-30de50dcbe96, // created_at: 2025-01-01T10:00:00Z, // transports: internal, // backup_eligible: true, // backup_state: true // }], // security_keys: [], // mfa_config: { auth_app_set_up: false, totp_enabled: false, security_keys_enabled: false }, // emails: [{ // id: f2882293-3c39-451d-a7cb-4cf3375e0c66, // address: userexample.com, // is_verified: true, // is_primary: true, // identities: [] // }], // username: { // id: a1b2c3d4-3c39-451d-a7cb-4cf3375e0c66, // username: johndoe, // created_at: 2025-01-01T10:00:00Z, // updated_at: 2025-01-01T10:00:00Z // }, // metadata: { public_metadata: {}, unsafe_metadata: {} }, // identities: [], // created_at: 2025-01-01T10:00:00Z, // updated_at: 2025-04-01T12:00:00Z, // name: John Doe, // given_name: John, // family_name: Doe // } } catch (error) { console.error(Failed to fetch user profile:, error); // Handle UnauthorizedError or TechnicalError }校验会话validateSession检查当前会话的有效性返回值一个SessionCheckResponse对象结构定义见 frontend/frontend-sdk/src/lib/Dto.ts包含is_valid布尔值会话是否有效expiration_time会话过期时间ISO 8601可选user_id会话所属用户 ID可选idle_expires_at配置了空闲超时后会话因无活动而过期的时间可选claims会话声明对象可选包括subject用户 ID 或会话标识session_id唯一会话标识expiration会话过期时间戳ISO 8601email邮箱详情对象如{ address: string, is_primary: boolean, is_verified: boolean }可选username用户名可选issued_at、audience、issuer会话 token 的元数据可选自定义声明由应用定义。错误TechnicalError服务端或网络问题。try { const sessionStatus await hanko.validateSession(); console.log(Session status:, sessionStatus); // Example output: // { // is_valid: true, // expiration_time: 2025-04-25T12:00:00Z, // user_id: 123e4567-e89b-12d3-a456-426614174000, // idle_expires_at: 2025-04-25T11:00:00Z, // claims: { // subject: 123e4567-e89b-12d3-a456-426614174000, // session_id: 789abc, // expiration: 2025-04-25T12:00:00Z, // email: { address: userexample.com, is_primary: true, is_verified: true }, // custom_field: value // } // } } catch (error) { console.error(Failed to validate session:, error); // Handle TechnicalError }Claims的完整类型定义在 frontend/frontend-sdk/src/lib/Dto.ts包含subject、issued_at、expiration、audience、issuer、email、username、session_id等标准声明并通过泛型参数支持扩展自定义声明。获取会话 TokengetSessionToken从认证 cookie 中读取当前会话 token返回值包含 JWT 会话 token 的字符串或null无会话时。注意该方法不会抛错请通过判断null来处理无会话的情况。const token hanko.getSessionToken(); console.log(Session token:, token); // Example output: eyJhbGciOiJIUzI1NiIs...其底层实现直接读取认证 cookieHanko.ts 调用cookie.getAuthCookie()。登出用户logout注销当前会话使会话失效返回值登出成功后 resolve无值的 Promise失败则抛错。错误TechnicalError服务端或网络问题。注意若当前不存在会话该方法也会正常 resolve不会报错。try { await hanko.logout(); console.log(User logged out); } catch (error) { console.error(Failed to fetch user logout:, error); // Handle TechnicalError }邮件翻译的语言配置如果使用Hanko主客户端可以在实例化时通过lang选项向 Hanko API 传递首选语言用于决定外出邮件的语言如登录验证码、安全通知等邮件。若通过 Hanko 发送邮件lang应与 Hanko 支持的语言之一匹配如bn、de、en、fr、it、nl、pt-BR、zh与仓库 mail/locales 目录下的本地化文件对应。若关闭了 Hanko 的邮件投递、改用email.send事件的 webhook则lang的值会体现在 webhook 请求所携带 token 的 JWT 载荷中的 Language 声明里。源码层面语言是通过自定义请求头X-Language传给 Hanko API 的此外 Hanko.ts 还提供了setLang(lang)方法可在运行时动态更新底层客户端的语言设置。自定义会话声明的类型安全Hanko 后端允许在签发的会话 JWT 中加入自定义声明会话 JWT 模板的说明见 backend/README.md。为了让 IDE 具备自动补全并保持自定义声明的类型安全可以按以下步骤操作在项目中创建 TypeScript 声明文件*.d.ts或直接修改现有声明文件从 Frontend SDK 导入Claims类型声明一个扩展Claims的自定义类型将自定义声明添加到该类型中import type { Claims } from teamhanko/hanko-frontend-sdk // 2. // import type { Claims } from teamhanko/elements // alternatively, if you use Hanko Elements, which // re-exports most SDK types type CustomClaims Claims{ // 3. custom_claim?: string // 4. };在访问声明时使用自定义类型例如事件回调中的会话详情或会话校验接口返回的 claimsimport type { CustomClaims } from ...; // path to your type declaration file hanko.onSessionCreated((sessionDetail) { const claims sessionDetail.claims as CustomClaims; console.info(My custom claim:, claims.custom_claim); });import type { CustomClaims } from ...; // path to your type declaration file async function session() { const session await hanko.validateSession(); const claims session.claims as CustomClaims; console.info(My custom claim:, claims.custom_claim); };底层机制上ClaimsTCustomClaims是一个泛型交叉类型标准声明字段与TCustomClaims约束为Recordstring, unknown取交集frontend/frontend-sdk/src/lib/Dto.ts因此自定义类型只需声明新增字段即可获得完整推导。FlowAPI用自定义前端驱动认证流程FlowAPI 是 SDK 提供的 TypeScript 接口用于管理 Hanko 的认证与个人资料流程支持开发完全自定义的前端。它在 State.ts 中实现负责状态转换、动作执行、输入校验与事件派发并内置自动步进auto-stepping与 passkey 自动填充autofill支持。核心概念一个流程Flow是一个自包含的状态机SDK 支持login、registration、profile、token_exchange四种顶层流程frontend/frontend-sdk/src/lib/flow-api/types/flow.ts。每个流程由若干状态State组成全部 26 个可能的状态名定义在 frontend/frontend-sdk/src/lib/flow-api/types/state.ts例如login_init、login_password、passcode_confirmation、success、error等每个状态下的可用动作Action及其输入Input、**载荷Payload**类型分别定义在 action.ts、input.ts 与types/payload.ts中。初始化一个新流程使用Hanko实例上的createState方法开启一个新的认证或个人资料流程。选项可控制事件派发与自动步进行为const state await hanko.createState(login, { dispatchAfterStateChangeEvent: true, excludeAutoSteps: [], loadFromCache: true, cacheKey: hanko-flow-state, });参数说明flowName流程名如login、register或profile注意源码中的合法取值实际为login | registration | profile | token_exchange见 flow.ts。optionsdispatchAfterStateChangeEventboolean— 状态变更后是否派发 onAfterStateChange 事件默认trueexcludeAutoStepsAutoStepExclusion— 要跳过的自动步进状态名数组或传all跳过全部自动步进默认nullloadFromCacheboolean— 是否尝试从 localStorage 加载缓存的状态默认truecacheKeystring— localStorage 缓存的键名默认hanko-flow-state。其底层逻辑State.ts为若loadFromCache为真且能在cacheKey下解析出有效缓存则反序列化恢复否则向服务端POST /{flowName}拉取初始状态。理解 State 对象state对象代表流程中的当前步骤包含以下属性与方法nameStateName— 当前状态名如login_init、login_password、successflowNameFlowName— 流程名如loginerrorError | undefined— 动作或请求失败时的错误对象如输入非法、网络错误payloadPayloads[StateName] | undefined— API 返回的该状态特有数据actionsActionMapStateName— 将动作名映射到Action实例的对象csrfTokenstring— 用于安全请求的 CSRF tokenstatusnumber— 上一次响应的 HTTP 状态码invokedActionActionInfo | undefined— 本状态上最近一次被运行的动作信息如有previousActionActionInfo | undefined— 引导进入当前状态的动作信息如有isCachedboolean— 该状态是否从 localStorage 加载cacheKeystring— 用于 localStorage 缓存的键excludeAutoStepsAutoStepExclusion— 被排除在自动步进之外的状态名数组。以上字段与 State.ts 中的类定义一一对应。此外若当前状态支持自动步进或 passkey 自动填充还会提供autoStep与passkeyAutofillActivation方法见下文。动作可用性Action Availability后端配置或用户状态/属性可能启用或禁用某些动作。通过访问动作的enabled属性即可判断if (state.actions.example_action.enabled) { await state.actions.example_action.run(); } else { console.log(Action is disabled); }实现上State.buildActionMap用Proxy包装动作映射访问一个后端未返回的动作名时会返回一个enabled false的禁用动作占位href 为空、描述为 Disabled action见 State.ts 与Action.createDisabled保证类型安全的同时不会让代码崩溃。访问动作输入Accessing Action Inputsstate.actions中的每个动作都有inputs属性描述其期望的输入字段。每个输入字段的结构由 input.ts 中的InputTValue接口定义包含name、type如string、boolean、value、min_length、max_length、required、hidden、error上次提交失败的校验错误以及allowed_values受限取值列表。console.log(state.actions.continue_with_login_identifier.inputs); // Example output: // { // identifier: { name: identifier, type: string, required: false }, // email: { name: email, type: string, required: false }, // username: { // name: username, // type: string, // required: true, // min_length: 3, // max_length: 20 // } // }运行动作Running an Action动作负责将流程推进到新状态。使用动作的run方法传入输入值与可选配置带类型收窄的基础示例if (state.name login_init) { const newState await state.actions.continue_with_login_identifier.run({ username: user1, }); // Triggers onBeforeStateChange and onAfterStateChange events // newState is the next state in the flow (e.g., login_password) }补充说明类型收窄通过判断state.name来确保该状态存在对应动作、且输入合法。事件默认情况下run会在执行动作前触发onBeforeStateChange在新状态加载后触发onAfterStateChange。校验错误若动作因输入非法失败格式或长度不符newState.error会被设为invalid_form_data且具体错误会挂到对应输入字段上见下方错误处理。动作执行的内部流程State.ts先校验动作是否启用禁用或已调用过会抛错记录invokedAction派发onBeforeStateChange将输入默认值与用户提交值合并为{ input_data, csrf_token }请求体提交到动作的href随后清理 localStorage 缓存最后以新响应初始化下一个状态。事件处理器Event HandlersSDK 通过 Hanko 实例派发事件以追踪状态变更对应监听方法在 Listener.ts 中定义。onBeforeStateChange在动作执行前触发适合展示加载态hanko.onBeforeStateChange(({ state }) { console.log(Action loading:, state.invokedAction); });onAfterStateChange在新状态加载后触发适合渲染 UI 或处理状态特有逻辑hanko.onAfterStateChange(({ state }) { console.log(Action load finished:, state.invokedAction); switch (state.name) { case login_init: state.passkeyAutofillActivation(); // Special handler for passkey autofill; requires an input field on the page with autocompleteusername webauthn (e.g., input typetext nameusername autocompleteusername webauthn /) so the browser can suggest and autofill passkeys when the user interacts with it. break; case login_password: // Render password input UI if (state.error) { console.log(Error:, state.error); // e.g., invalid_form_data } break; case error: // Handle network errors or 5xx responses console.error(Flow error:, state.error); break; } });控制 afterStateChange 事件可以关闭自动派发的onAfterStateChange事件在自定义逻辑完成后手动派发if (state.name login_init) { const newState await state.actions.continue_with_login_identifier.run( { username: user1 }, { dispatchAfterStateChangeEvent: false }, // Disable automatic dispatch ); // Only onBeforeStateChange is triggered here await doSomething(); // Your custom async logic newState.dispatchAfterStateChangeEvent(); // Manually trigger the event }State构造时若dispatchAfterStateChangeEvent为真会在初始化时自动派发Action.run的config同样支持该选项State.ts。dispatchAfterStateChangeEvent()方法本身通过hanko.relay派发hanko-after-state-change事件State.ts。自动步进Auto-Steps自动步进会在特定状态自动推进流程减少手动干预。支持自动步进的状态preflightlogin_passkeyonboarding_verify_passkey_attestationwebauthn_credential_verificationthirdpartysuccessaccount_deleted这些状态与 auto-steps.ts 和 flow.ts 中的映射一致各自动步进的行为如下preflight自动上报客户端 WebAuthn 能力webauthn_available、webauthn_conditional_mediation_available、webauthn_platform_authenticator_available执行register_client_capabilities动作login_passkey自动发起 WebAuthn 断言并提交webauthn_verify_assertion_response失败时回退并保留服务端错误onboarding_verify_passkey_attestation/webauthn_credential_verification自动创建 WebAuthn 凭证并提交 attestation 响应InvalidStateError会被翻译为凭证已存在错误thirdparty自动处理 OAuth 回调——从 URL 读取hanko_token并调用exchange_token配合 PKCE code_verifier处理error参数与access_denied映射无 token 时保存状态并跳转到redirect_urlsuccess派发hanko-session-created事件并清理缓存account_deleted派发hanko-user-deleted事件并清理缓存。禁用自动步进通过excludeAutoSteps指定要跳过的状态const state await hanko.createState(login, { excludeAutoSteps: [success], // Skip auto-step for success });createState的初始化流程会循环执行自动步进直到到达无自动步进的状态或命中被排除的状态State.ts。手动执行自动步进hanko.onAfterStateChange(({ state }) { if (state.name success) { console.log(Flow completed); await state.autoStep(); } });错误处理Error Handling输入错误动作因输入非法失败时if (state.name login_password state.error invalid_form_data) { const passwordError state.actions.password_login.inputs.password.error; console.log(Password error:, passwordError); }具体错误的错误码类型定义在 frontend/frontend-sdk/src/lib/flow-api/types/flowError.ts 中服务端返回的每个输入字段校验错误会被解析并挂载到对应Input.error上。网络 / API 错误网络问题或5xx响应会使流程进入error状态详情在state.error中if (state.name error) { console.error(Flow error:, state.error); }当请求失败时State.fetchState会捕获异常并构造一个名为error、status: 0的错误状态State.ts保证流程不会在 HTTP 层直接中断。缓存流程状态Caching Flow State使用localStorage持久化与恢复流程状态适合刷新页面后继续未完成的流程。保存状态state.saveToLocalStorage(); // Stores under state.cacheKey (default: hanko-flow-state)注意一旦在保存的状态上调用动作localStorage 中的该条目会被自动移除见 State.ts 中run对removeFromLocalStorage的调用。加载状态const state await hanko.createState(login, { loadFromCache: true, // Attempts to load from cacheKey cacheKey: hanko-flow-state, });清除状态state.removeFromLocalStorage(); // Deletes from state.cacheKey高级序列化用于自定义持久化机制import { State } from teamhanko/hanko-frontend-sdk; const serialized state.serialize(); // Returns a SerializedState object // Store serialized in your storage system // Later, deserialize it const recoveredState await State.deserialize(hanko, serialized, { cacheKey: custom-key, });serialize()会把状态含flow_name、name、error、payload、csrf_token、status、previous_action与动作映射转成可存储的普通对象State.deserialize则将其恢复为可用状态State.ts、State.ts。这允许与任意存储系统集成。测试与源码参考FlowAPI 与各子系统的行为在仓库测试中有充分覆盖可作为理解与二次开发的参考frontend/frontend-sdk/tests/lib/flow-api/State.spec.ts状态创建、动作执行、缓存与反序列化frontend/frontend-sdk/tests/lib/flow-api/auto-steps.spec.ts自动步进行为frontend/frontend-sdk/tests/lib/client/HttpClient.spec.ts、frontend/frontend-sdk/tests/lib/client/UserClient.spec.tsHTTP 客户端与用户接口frontend/frontend-sdk/tests/lib/events/Dispatcher.spec.ts、frontend/frontend-sdk/tests/lib/events/Listener.spec.ts事件派发与监听。许可证hanko-frontend-sdk以 MIT License 授权发布。赞分享后端认证鉴权前端【免费下载链接】hankoModern authentication, on your terms. Open source alternative to Auth0, Clerk, WorkOS, Stytch.项目地址https://gitcode.com/GitHub_Trending/ha/hanko点击查看免费下载相关推荐openJiuwen DeepSearch人机协同自然语言反馈与交互式修订完整指南openJiuwen DeepSearch人机协同自然语言反馈与交互式修订完整指南 openJiuwen DeepSearch 是一款知识增强的深度搜索与研究人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体GoCD与Netlify Identity集成前端认证部署完整指南GoCD与Netlify Identity集成前端认证部署完整指南 GoCD是一个开源的持续集成和持续部署工具可以帮助开发团队自动化软件开发和运维流程。通过CI/CDDevOps后端任务调度jeecg-boot前端表单验证VeeValidate集成与自定义校验规则完整指南jeecg boot前端表单验证VeeValidate集成与自定义校验规则完整指南 你是否在开发企业级管理系统时遇到过表单验证的困扰jeecg boot作为低代码后端前端AI 应用大模型RAG工作流自动化上一篇如何高效管理EVE Online舰船配置Pyfa开源工具深度解析下一篇Goldfish安全架构揭秘如何实现零信任的密钥管理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网