Hanko:开源、无密码优先的身份认证与用户管理平台

GitHub: https://github.com/teamhanko/hanko · 官方文档: https://docs.hanko.io

Hanko 是一个开源的认证与用户管理平台,框架无关、易于集成,遵循隐私优先原则(数据最小化、防钓鱼),支持自托管,也提供全托管的 Hanko Cloud。仓库整体以 AGPL-3.0 开源,其中 elements/ 目录另有授权条款(见仓库 LICENSE)。

简介

Hanko 用一句话概括:一个后端 API + 一组前端组件,即可为自己的应用接入现代登录体验。它把密码、Passkey、邮箱验证码等认证方式的繁琐细节全部封装好,开发者不必自己实现 WebAuthn 与令牌体系。

仓库主要由三大块组成(backend/frontend/):

组件位置作用
Hanko backendbackend/Go 编写的认证 API:密码、Passkey、邮箱 Passcode、用户与会话管理、JWT 签发
hanko-elementsfrontend/elements/Web Components,提供开箱即用的登录/注册/个人资料 UI,可用 CSS 定制
hanko-frontend-sdkfrontend/frontend-sdk/浏览器端 JS 客户端,封装与 backend API 的通信

其余部分:quickstart/(参考实现示例应用)、deploy/(docker-compose 编排)、e2e/(端到端测试)。文档已迁移到独立仓库 teamhanko/docs

能力全景(来自官方 README):

快速上手:Docker Compose 一键起全套

最省事的方式是用仓库自带的 quickstart.yaml(含 backend、Postgres、前端组件、示例应用、Mailslurper):

git clone https://github.com/teamhanko/hanko.git cd hanko docker compose -f deploy/docker-compose/quickstart.yaml -p "hanko-quickstart" up --build

启动后访问:

地址内容
http://localhost:8888登录/注册演示页(quickstart 应用)
http://localhost:8080Mailslurper Web UI(捕获发出的 passcode 邮件)
http://localhost:8000backend Public API(默认端口)
http://localhost:8001backend Admin API
http://localhost:8002backend Management API

也可以直接体验线上样例 https://example.hanko.iohttps://www.passkeys.io。

手动部署 Hanko backend

不想用 compose 时,可按官方文档顺序手动搭建:数据库 → 配置 → 迁移 → SMTP → 启动。

1. 运行数据库(PostgreSQL 或 MySQL)

docker run --name=postgres \ -e POSTGRES_USER=hanko -e POSTGRES_PASSWORD=hanko -e POSTGRES_DB=hanko \ -p 5432:5432 -d postgres

2. 从源码构建二进制(需 Go 1.18+)

cd backend go generate ./... go build -a -o hanko main.go

3. 编写 config.yaml

database: user: hanko password: hanko host: localhost port: 5432 database: hanko dialect: postgres # 或 mysql secrets: keys: - CHANGE-ME-TO-A-RANDOM-SECRET-AT-LEAST-16-CHARS # 必填,至少 1 个,用于加密签发 JWT 的 JWK service: name: My Authentication Service email_delivery: enabled: true email: from_address: no-reply@example.com from_name: Example App smtp: host: localhost # 本地调试可用 Mailslurper (端口 2500) port: 2500 webauthn: relying_party: id: "example.com" display_name: "Example Project" origins: - "https://example.com" server: public: cors: allow_origins: - "https://example.com"

secrets.keys 至少需要 1 个条目,且每条必须是至少 16 字符的随机串;JWK 由该密钥加解密后持久化,并通过 /.well-known/jwks.json 发布公钥供客户端验签。

4. 迁移数据库并启动

./hanko migrate up --config ./config.yaml # 应用数据库迁移 ./hanko serve all --config ./config.yaml # 同时启动 public + admin

hanko CLI 常用命令速查

编译出的 ./hanko 二进制提供以下子命令;Docker 形态等价于 docker run --mount type=bind,source=<配置绝对路径>,target=/config/config.yaml -p 8000:8000 ghcr.io/teamhanko/hanko:latest <子命令>

命令说明
./hanko serve public启动 Public API(默认 :8000,配置项 server.public.address
./hanko serve admin启动 Admin API(默认 :8001,需自备访问管控!)
./hanko serve management启动 Management API(默认 :8002)
./hanko serve all同时启动 public + admin
./hanko migrate up / ./hanko migrate down应用 / 回滚数据库迁移
./hanko user import -i users.json按 JSON 文件批量导入用户(也支持 -u/--inputUrl
./hanko user export把用户导出为 JSON 文件
./hanko jwt create [user_id]签发调试用 JWT
./hanko jwk create生成签名用 JWK
./hanko config show打印当前生效配置
./hanko isready健康检查
./hanko version版本号

所有命令通常配合 --config <路径> 指定配置文件(相对/绝对路径均可)。Admin API 与 Management API 必须部署在受访问管控保护的网络内。

config.yaml 关键配置速查

配置块关键字段说明
databaseuser/password/host/port/database/dialect数据库连接;dialect 支持 postgres / mysql
secretskeys[]JWK 加解密密钥,≥16 字符随机串,至少 1 个
servicename服务名,用于邮件 subject 等
email_deliveryenabledemail.from_addresssmtp.host/port/user/passwordSMTP 发信(passcode、验证、找回密码邮件)
webauthnrelying_party.id/display_name/origins[]WebAuthn 依赖方;id 填域名,origins 含协议与端口
server.publiccors.allow_origins[]address前端域名白名单与监听地址;* 通配需同时设 unsafe_wildcard_origin_allowed: true
server.ipextractortrusted_proxies[]客户端 IP 解析:direct(默认)/ x_forwarded_for / x_real_ip(后两者须配可信代理网段)
passwordenabledmin_password_length密码登录开关,默认关闭
sessionenable_auth_token_headercookie.securelifespan跨域场景用 X-Auth-Token 头传 JWT(默认 cookie)
session.jwt_templateclaims自定义 JWT 声明,支持 Go text/template + GJSON 读取用户元数据
mfatotp.enabledsecurity_keys.enabledoptional二步验证:TOTP / 安全密钥,可设备信任
third_partyproviders.*custom_providers.*redirect_urlOAuth 社交登录;内置提供方默认禁用,需显式 enabled + client_id/secret
webhooksenabledhooks[].callback/events[]事件回调通知
audit_logconsole_output.enabledstorage.enabled审计日志:默认打 STDOUT,可持久化到数据库

前端集成:hanko-elements

Web Components 版的接入只需要两步:安装 → register() → 页面放组件。

npm install @teamhanko/hanko-elements # 或 yarn add / pnpm install @teamhanko/hanko-elements

最小可用页面(官方示例):

<hanko-auth></hanko-auth> <script type="module"> import { register } from "https://cdn.jsdelivr.net/npm/@teamhanko/hanko-elements/dist/elements.js"; const { hanko } = await register("https://hanko.yourdomain.com"); hanko.onSessionCreated(() => { window.location.href = "/secured"; // 登录成功后的跳转 }); </script>

register(apiUrl, options) 支持的关键选项:shadow(默认 true,挂 shadow DOM)、injectStylesenablePasskeystranslationscookieDomaincookieSameSitesessionCheckInterval(毫秒,须 > 3000)。

可用组件:

组件用途
<hanko-auth>登录 + 注册二合一 UI(可 mode="login\|registration" 指定初始流程)
<hanko-login> / <hanko-registration>仅登录 / 仅注册
<hanko-profile>个人资料管理:邮箱、密码、Passkey、MFA
<hanko-events>不渲染 UI,仅用于绑定会话事件

组件公共属性:lang(语言)、nonce(CSP 内联样式)、prefilled-emailprefilled-username 等。UI 定制可通过 CSS Variables / CSS Shadow Parts 完成,无需改组件源码。

前端集成:hanko-frontend-sdk

自建 UI 时用 JS SDK 直接调用 backend API:

import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko("http://localhost:8000", { timeout: 13000, // 请求超时(ms) cookieName: "hanko", // 会话 cookie 名 localStorageKey: "hanko", // localStorage 前缀 sessionCheckInterval: 30000, // 会话有效性轮询间隔(ms),必须 > 3000 });

会话事件绑定(返回移除监听器的函数):

// 会话创建(登录成功 / 新 JWT 签发),可获得 JWT claims const off = hanko.onSessionCreated((sessionDetail) => { console.info("Session created", sessionDetail.claims); }); // 会话过期或被远端吊销 hanko.onSessionExpired(() => { /* 跳转登录页 */ }); // 登出 hanko.onUserLoggedOut(() => { /* ... */ });

Webhooks:感知用户变更

开启并配置回调端点(回调需返回 HTTP 200,否则视为投递失败):

webhooks: enabled: true hooks: - callback: https://example.com/hook events: - user # 订阅父事件,接收全部子事件

每个事件会 POST 一个 JSON:{ "event": "事件名", "token": "<JWT>" },JWT 内含两个自定义声明:evt(事件名)与 data(变更对象全文,可用 secrets.keys 对应的 JWK 解码验签)。

支持的事件(可细分订阅子事件):

事件触发时机
user用户/邮箱的创建、删除、更新(含主邮箱变更)
user.create / user.delete用户创建 / 删除
user.login用户登录
user.update.email.create/delete/primary邮箱创建 / 删除 / 设为主邮箱
user.update.username.create/delete/update用户名的增删改
email.send邮件发送(或准备发送)

进阶:自定义会话 JWT 声明

通过 session.jwt_template.claims 在签发 JWT 时注入自定义声明,模板可访问用户上下文 .User(含 .User.UserID.User.Email.Address.User.Username.User.Metadata.Public/Unsafe 等),元数据用 GJSON 路径语法读取:

session: jwt_template: claims: role: "user" # 静态值 user_email: "{{ .User.Email.Address }}" # 模板字符串 is_verified: "{{ .User.Email.IsVerified }}" # 布尔值 display_name: '{{ .User.Metadata.Public "display_name" }}' # 读公开元数据 scopes: - "read" - "write" - "{{if .User.Email.IsVerified}}admin{{else}}basic{{end}}" # 条件模板

subiatexpissemailsession_id 等保留键会被忽略;模板需符合 Go text/template 语法,非法模板会被记录并排除。

相关链接