news 2026/10/2 1:37:19

Hanko Frontend SDK 完整指南:浏览器端认证集成与 FlowAPI 自定义前端开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hanko Frontend SDK 完整指南:浏览器端认证集成与 FlowAPI 自定义前端开发
  • 后端
  • 认证鉴权
  • 前端

【免费下载链接】hanko

Modern 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.cjs(CommonJS)、dist/sdk.modern.js(ESM)以及dist/sdk.umd.js(UMD),分别通过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 src="https://cdn.jsdelivr.net/npm/@teamhanko/hanko-frontend-sdk/dist/sdk.umd.js"></script> <script> const hanko = new hankoFrontendSdk.Hanko("http://localhost:3000") ... </script>

UMD 构建会把全部导出挂载到全局命名空间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 请求超时时间(毫秒)
cookieNamestring"hanko"SDK 写入会话 token 的 cookie 名
cookieDomainstring当前页面域名cookie 生效的域名
cookieSameSiteCookieSameSite"lax"跨站请求时 cookie 的发送策略
localStorageKeystring"hanko"localStorage 键名前缀
langstring—向 API 传递的首选语言(见下文"邮件翻译")
sessionCheckIntervalnumber30000会话有效性轮询间隔(毫秒),必须大于 3000,否则强制设为 3000
sessionCheckChannelNamestring"hanko-session-check"跨标签页通信的 BroadcastChannel 名称
sessionTokenLocation"cookie" \| "sessionStorage"—会话 token 的存储位置

其中sessionCheckInterval的最小值约束在 Relay.ts 中实现:若传入值小于 3000 会被直接钳制为 3000。而sessionCheckChannelName在sessionTokenLocation为"sessionStorage"时,会以该值为前缀生成随机通道名并持久化到sessionStorage,用于区分不同标签页间的会话同步(见 Relay.ts)。

会话事件(Session Events)

SDK 基于浏览器原生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 的 claims:

hanko.onSessionCreated((sessionDetail) => { // A new JWT has been issued. console.info("Session created", sessionDetail.claims); })

从源码看,SessionDetail包含claims(JWT 声明对象)与已废弃的expirationSeconds字段(frontend/frontend-sdk/src/lib/events/CustomEvents.ts)。该事件在success状态的 auto-step 中被派发:SDK 从成功载荷中取出 claims,计算剩余有效期后调用dispatchSessionCreatedEvent(frontend/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-expired:

hanko.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-expired:

hanko.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 Management)

SDK 提供一组用于管理用户会话与获取用户信息的方法,均由 Hanko.ts 中的Hanko类直接暴露。

获取用户对象(getCurrentUser)

拉取当前用户的完整资料:

  • 返回值:一个User对象,包含:
    • user_id:用户的唯一字符串标识;
    • passkeys:已注册 passkey 数组(WebauthnCredential[],可选);
    • security_keys:已注册安全密钥数组(WebauthnCredential[],可选);
    • mfa_config:MFA 配置对象({ 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_at:ISO 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: "user@example.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 8601);
      • email:邮箱详情对象(如{ 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: "user@example.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等标准声明,并通过泛型参数支持扩展自定义声明。

获取会话 Token(getSessionToken)

从认证 cookie 中读取当前会话 token:

  • 返回值:包含 JWT 会话 token 的字符串,或null(无会话时)。
  • 注意:该方法不会抛错;请通过判断null来处理无会话的情况。
const token = hanko.getSessionToken(); console.log("Session token:", token); // Example output: "eyJhbGciOiJIUzI1NiIs..."

其底层实现直接读取认证 cookie(Hanko.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 具备自动补全并保持自定义声明的类型安全,可以按以下步骤操作:

  1. 在项目中创建 TypeScript 声明文件(*.d.ts,或直接修改现有声明文件);
  2. 从 Frontend SDK 导入Claims类型;
  3. 声明一个扩展Claims的自定义类型;
  4. 将自定义声明添加到该类型中:
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. }>;
  1. 在访问声明时使用自定义类型,例如事件回调中的会话详情,或会话校验接口返回的 claims:
import 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); };

底层机制上,Claims<TCustomClaims>是一个泛型交叉类型:标准声明字段与TCustomClaims(约束为Record<string, 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)。
  • options:
    • dispatchAfterStateChangeEvent:boolean— 状态变更后是否派发 onAfterStateChange 事件(默认true);
    • excludeAutoSteps:AutoStepExclusion— 要跳过的自动步进状态名数组,或传"all"跳过全部自动步进(默认null);
    • loadFromCache:boolean— 是否尝试从 localStorage 加载缓存的状态(默认true);
    • cacheKey:string— localStorage 缓存的键名(默认"hanko-flow-state")。

其底层逻辑(State.ts)为:若loadFromCache为真且能在cacheKey下解析出有效缓存,则反序列化恢复;否则向服务端POST /{flowName}拉取初始状态。

理解 State 对象

state对象代表流程中的当前步骤,包含以下属性与方法:

  • name:StateName— 当前状态名(如"login_init"、"login_password"、"success");
  • flowName:FlowName— 流程名(如"login");
  • error:Error | undefined— 动作或请求失败时的错误对象(如输入非法、网络错误);
  • payload:Payloads[StateName] | undefined— API 返回的该状态特有数据;
  • actions:ActionMap<StateName>— 将动作名映射到Action实例的对象;
  • csrfToken:string— 用于安全请求的 CSRF token;
  • status:number— 上一次响应的 HTTP 状态码;
  • invokedAction:ActionInfo | undefined— 本状态上最近一次被运行的动作信息(如有);
  • previousAction:ActionInfo | undefined— 引导进入当前状态的动作信息(如有);
  • isCached:boolean— 该状态是否从 localStorage 加载;
  • cacheKey:string— 用于 localStorage 缓存的键;
  • excludeAutoSteps:AutoStepExclusion— 被排除在自动步进之外的状态名数组。

以上字段与 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 Inputs)

state.actions中的每个动作都有inputs属性,描述其期望的输入字段。每个输入字段的结构由 input.ts 中的Input<TValue>接口定义:包含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 Handlers)

SDK 通过 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 `autocomplete="username webauthn"` (e.g., <input type="text" name="username" autocomplete="username 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)

自动步进会在特定状态自动推进流程,减少手动干预。

支持自动步进的状态
  • preflight
  • login_passkey
  • onboarding_verify_passkey_attestation
  • webauthn_credential_verification
  • thirdparty
  • success
  • account_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_url;
  • success:派发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.ts:HTTP 客户端与用户接口;
  • frontend/frontend-sdk/tests/lib/events/Dispatcher.spec.ts、frontend/frontend-sdk/tests/lib/events/Listener.spec.ts:事件派发与监听。

许可证

hanko-frontend-sdk以 MIT License 授权发布。

  • 后端
  • 认证鉴权
  • 前端

【免费下载链接】hanko

Modern authentication, on your terms. Open source alternative to Auth0, Clerk, WorkOS, Stytch.

项目地址:https://gitcode.com/GitHub_Trending/ha/hanko
点击查看免费下载

相关推荐

上一篇:如何高效管理EVE Online舰船配置:Pyfa开源工具深度解析
下一篇:Goldfish安全架构揭秘:如何实现零信任的密钥管理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 1:35:51

一键开关机芯片选型指南:功耗、时序与可靠性的四维实战分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 1:35:47

电信CRM设计系统:核心域、数据模型与文档落地要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 1:35:36

一体化多参数超声波气象设备:原理、选型、部署与排障实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 1:35:06

STM32参考设计全解析:从找资源到抄板调试的实用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 1:34:27

Windows 上搭建 ESP32-C3 开发环境:ESP-IDF 与 VS Code 集成实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 1:33:51

ESP32无MMU下的沙箱设计:分层设防与API白名单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华