Keycloak 前端本地开发实战:用 keycloak-server 一键启动服务器并打通 Vite 热更新

原创2026-09-08 11:47:071,434 阅读
文章标签:认证鉴权后端单点登录身份认证

Keycloak 前端本地开发实战:用 keycloak-server 一键启动服务器并打通 Vite 热更新

适用模块:keycloak-server(js 前端工作区下的私有开发工具)|仓库根:GitHub_Trending/ke/keycloak

导读:在为本仓库的 admin-ui(新版 Admin Console) 与 account-ui(新版 Account Console) 等前端应用做日常开发时,你几乎总是需要一个可随时重启、版本对得上、行为接近线上发布的 Keycloak 服务器做后端载体。keycloak-server 就是这样一个专门的本地启动器:它负责自动下载官方 Nightly 版 Keycloak 发行包、解压到本地缓存并以 start-dev 模式拉起进程,同时通过环境变量把 Vite 开发服务器"接"进 Keycloak,让你改前端代码即可热更新、无需手工重启。读完本文,你将掌握它提供的全部命令与参数、脚本内部的执行细节,以及两种让前端 Vite 与 Keycloak 联调的标准化姿势。


一、先厘清定位:它不是库,而是一个"一键启动器"

先明确一点:keycloak-server 是一个 "private": true 的私有 pnpm workspace 应用,不会被发布,也不提供任何可供业务复用的 API。它在 package.json 中只暴露三个脚本:

npm script 底层命令 作用
start node ./scripts/start-server.js 下载(或复用缓存)Keycloak 并以 start-dev 模式启动
delete-data rm -r ./server/data 只清空服务器运行数据,下次启动复用已下载的发行包
delete-server rm -r ./server 删除本地缓存的整个服务器发行包,下次启动强制重新下载

它的全部逻辑集中在入口脚本 scripts/start-server.js,依赖也很精简:@octokit/rest(调用 GitHub Release API 定位 Nightly 构建产物)、gunzip-maybe + tar-fs(流式解压 tar.gz)、node:child_process(拉起 Keycloak 进程)。从源码结构可以清晰看出,这个模块想解决的核心问题只有两个:"去哪拿一份 Keycloak" 与 "怎么把它和前端开发服务器接起来"。

二、快速开始:安装依赖并一键启动

按照 README 的标准流程,首先在 pnpm 工作区安装依赖:

pnpm install

本仓库 js 前端侧使用 PNPM 作为包管理器(仓库 js/ 目录下存在 pnpm-workspace.yaml 与 package.json);也可以参考 js/CODING_GUIDELINES.md 中的建议先执行 corepack enable 来锁定正确版本。

依赖装好后,启动本地 Keycloak:

pnpm start

若希望服务器对接本地正在开发的 Vite 前端,需要追加 --admin-dev 或 --account-dev 标志:

pnpm start --admin-dev
pnpm start --account-dev

其中:

命令执行后,Keycloak 会运行在本机 8080 端口,可用浏览器直接访问;而真实的 JS/TS 源码改动则通过下文介绍的 Vite 代理实时反映到页面上。

三、启动脚本内部究竟做了什么(源码级拆解)

为了让"一键启动"不黑盒,这里结合 start-server.js 逐段说明实际执行流程。

3.1 参数解析:脚本自有参数与 Keycloak 参数分离

脚本用 Node.js 内置的 node:util 的 parseArgs 声明了三个布尔选项 local、account-dev、admin-dev(见 L22-L32),再通过 tokens 方式把不属于这三个选项的参数原样剔除出来(见 L77-L94):

const options = {
  local: { type: "boolean" },
  "account-dev": { type: "boolean" },
  "admin-dev": { type: "boolean" },
};

剔除逻辑的关键在于 tokens.filter((token) => Object.hasOwn(options, token.name))——只移除脚本自身认识的标志,其余全部保留为 keycloakArgs。这正是 README 那句 "All other arguments will be passed through to the underlying Keycloak server" 的代码出处。

3.2 获取发行包:缓存优先,Nightly 兜底

downloadServer(local)(见 L97-L117)首先检查缓存目录是否存在:

const directoryExists = fs.existsSync(SERVER_DIR);
if (directoryExists) {
  console.info("Server installation found, skipping download.");
  return;
}

其中缓存目录 SERVER_DIR 被解析为脚本上级的 server/ 目录,即 js/apps/keycloak-server/server/。也就是说:只要本地已有解压好的发行包,脚本就不会重复下载;只有首次运行、或你手动删掉 server/ 之后,才会走下载分支。

默认下载源是官方 Nightly 版本:脚本用 Octokit 调用 GitHub Releases API,读取 tag: "nightly" 的发布,从中挑选名为 keycloak-999.0.0-SNAPSHOT.tar.gz 的资产(见 L119-L130)。随后用 fetch 把资产下载为流,经 gunzip-maybe 解压、tar-fs 以 strip: 1 剥掉顶层目录后落入 server/(见 L132-L143)。

理解这一点对排查很有价值:

  • Nightly 是滚动构建,版本号固定为 999.0.0-SNAPSHOT,内容每天可能不同,因此今天能正常联调不代表缓存永远适用;
  • 当你怀疑"缓存里的服务器与当前前端代码不匹配"时,最干脆的复位手段就是 pnpm delete-server 强制重下一次(见 package.json);
  • 下载过程需要能访问 GitHub Releases 的网络环境,否则首次启动会在该步骤失败。

3.3 启动前注入环境变量

启动前(见 L41-L55),脚本先构造一组默认环境变量:

const env = {
  KC_BOOTSTRAP_ADMIN_USERNAME: "admin",
  KC_BOOTSTRAP_ADMIN_PASSWORD: "admin",
  KC_BOOTSTRAP_ADMIN_CLIENT_ID: "temporary-admin-service",
  KC_BOOTSTRAP_ADMIN_CLIENT_SECRET: "temporary-admin-service",
  ...process.env,
};

即:本地管理员账号为 admin / admin,同时预置了一个名为 temporary-admin-service 的引导用服务账号。随后若带 --account-dev / --admin-dev,会继续注入两个 Vite 联调环境变量(见 L49-L55):

if (scriptArgs["account-dev"]) env.KC_ACCOUNT_VITE_URL = "http://localhost:5173";
if (scriptArgs["admin-dev"])   env.KC_ADMIN_VITE_URL = "http://localhost:5174";

这正是两个标志与下一节"纯环境变量方案"等价的原因——标志本质上就是替你写好这两行环境变量。

3.4 拉起 Keycloak:start-dev + 预置特性集

最后脚本以 shell: true 方式启动缓存目录下的 bin/kc(Windows 下为 kc.bat,见 L59-L71),固定参数为:

bin/kc start-dev \
  --features="ssf,transient-users,oid4vc-vci,declarative-ui,quick-theme,spiffe,kubernetes-service-accounts,workflows,client-auth-federated,openapi,client-admin-api:v2" \
  --openapi-enabled=true

随后拼上前面分离出来的 keycloakArgs(用户透传参数),并把子进程的 stdout/stderr 接到当前终端。

从中可以得到两个可直接引用的事实:

  1. 它走的是 start-dev(开发模式),即无需 TLS、使用开发默认配置的本地运行形态;
  2. 启动时默认开启了一批实验性/开发用特性——transient-users(临时用户)、oid4vc-vci(OID4VC 凭据签发)、ssf、declarative-ui、quick-theme、spiffe、workflows、client-auth-federated、openapi 以及带版本号的 client-admin-api:v2。README 中"纯环境变量方案"示例里给出的 KC_FEATURES=login:v2,account:v3,admin-fine-grained-authz,transient-users,oid4vc-vci 是另一种等效的独立开关写法——不同写法所开的特性集由对应分支的代码现状决定,改动前请以仓库当时实际代码为准。

说明:--features 与 --openapi-enabled 均为脚本写死的启动参数;其真实生效范围以你下载到的那个发行包所支持的选项为准。

四、缓存与数据管理:delete-server 与 delete-data

本地开发最怕两种状态:服务器版本过旧、脏数据干扰验证。README 给出了两个差异明确的清理命令:

# 1) 连发行包一起删:下次 pnpm start 将重新下载最新 Nightly
pnpm delete-server

# 2) 只清数据,保留已下载的发行包:更快地"重置现场"
pnpm delete-data

两者的差别一目了然(对应 package.json 中 delete-data 删除 ./server/data、delete-server 删除 ./server):

场景 推荐命令 效果 下次启动成本
服务器与前端代码版本可能不匹配、怀疑特性集不一致 pnpm delete-server 删除 js/apps/keycloak-server/server/ 整个发行包目录 需重新联网下载 Nightly
只要干净的 Realm/用户数据(如测试被污染、想从零验证导入流程) pnpm delete-data 仅删除 server/data 运行数据 秒级复用本地发行包

结合 3.2 节可知:server/ 目录同时充当"下载缓存"与"运行数据"的容器,所以这两条命令被设计为互补的复位手段。若你只想让数据区回到初始状态而保留二进制,务必选择 delete-data,避免无谓的重复下载。

五、与 Vite 前端联调:两种等效姿势与端口对照

5.1 姿势一:脚本标志(推荐给新同事)

pnpm start --admin-dev    # Admin Console 前端接 Vite
pnpm start --account-dev  # Account Console 前端接 Vite
pnpm start --admin-dev --account-dev  # 两者同时接 Vite

5.2 姿势二:手动设置环境变量(绕过脚本独立运行)

不通过本启动器、而要用已自行构建的 Keycloak 直连 Vite 时,设置如下环境变量即可达到同样效果(README 原文示例):

KC_ACCOUNT_VITE_URL=http://localhost:5173
KC_ADMIN_VITE_URL=http://localhost:5174
KC_FEATURES=login:v2,account:v3,admin-fine-grained-authz,transient-users,oid4vc-vci

5.3 端口从哪来:与两个前端工程一一对应

5173 / 5174 并非随手写的端口,而是两个前端工程各自 Vite dev server 的固定监听地址,均可在代码中查到:

映射关系整理如下:

标志 注入的环境变量 对应的 Vite dev server 对应前端工程
--account-dev KC_ACCOUNT_VITE_URL=http://localhost:5173 端口 5173 js/apps/account-ui
--admin-dev KC_ADMIN_VITE_URL=http://localhost:5174 端口 5174 js/apps/admin-ui

联调原理(来自源码与工程指南):你在浏览器里访问的仍然是 8080 端口的 Keycloak,但 Keycloak 收到这两个环境变量后会把对应控制台的静态资源请求反向代理到本地 Vite dev server(js/CODING_GUIDELINES.md 中原文为 "We run the UI in dev mode and configure keycloak to proxy the request")。因此前端源码的改动会由 Vite 以 HMR/热更新方式实时反映,无需刷新 Keycloak 或重启后端进程。完整联调流程(结合 js/CODING_GUIDELINES.md 的 "Running" 一节)为:

# 终端 A:先启动后端载体(自动注入 KC_ADMIN_VITE_URL 等)
pnpm --filter keycloak-server start --admin-dev

# 终端 B:再启动 admin-ui 的 Vite dev server
pnpm --filter keycloak-admin-ui run dev

之后浏览器打开 Keycloak(8080 端口)进入 Admin Console,使用的即是你本地最新源码,修改即时可见。Account Console 侧同理换成 --account-dev + pnpm --filter keycloak-account-ui run dev。

需要提醒的是,这套"代理热更新"只有在 Keycloak 侧加载的是 v2/v3 新主题时才成立——从两个工程的构建产物路径也能印证:admin-ui 构建输出到 theme/keycloak.v2/admin/resources(见 admin-ui/vite.config.ts 的 outDir),account-ui 构建输出到 theme/keycloak.v3/account/resources(见 account-ui/vite.config.ts),这正是前面 login:v2 / account:v3 等特性开关存在的原因。

六、使用本地 Quarkus 发行版:--local 标志

默认走 Nightly 下载需要外网且版本随上游滚动;如果你希望使用自己在本仓库用 Maven 构建出的 Quarkus 发行版来做前后端完全同源验证,则改用:

pnpm start --local

脚本中的查找逻辑(见 start-server.js L12-L15、L106-L110)表明它会在如下位置寻找本地构建产物:

js/apps/keycloak-server/scripts 上溯四层 → 仓库根 quarkus/dist/target/
  期望文件:keycloak-999.0.0-SNAPSHOT.tar.gz

即 quarkus/dist/target/keycloak-999.0.0-SNAPSHOT.tar.gz(quarkus/dist 属于 Maven 构建产物目录,需先完成对应模块的构建才会生成)。找到后它走的是与下载分支相同的 extractTarball 逻辑(strip: 1 解压到 server/),后续启动流程完全一致。这一模式适合:想调试尚未进入 Nightly 的 Quarkus 侧改动、或对发行包做了本地裁剪、需要离线复现的场景。

七、透传参数:让脚本"让位"给底层 Keycloak

README 特别强调:除 --local / --admin-dev / --account-dev 之外的一切参数都会被原样透传给底层的 Keycloak 服务器。这在 handleArgs 的实现中已被证实(见 3.1 节)。因此你不需要为每个 Keycloak 选项在脚本上再加一层包装,例如:

pnpm start --admin-dev --debug

--debug 会被原样交给 bin/kc start-dev 执行;同理,任何 start-dev 模式支持的选项(主机名、数据库、日志等配置开关)都可以这样透传。需注意透传参数与脚本预置参数(--features、--openapi-enabled=true)共存时的优先级,以底层发行包实际行为为准。

八、常见使用误区小结

误区 正确理解
以为每次 pnpm start 都会下载新服务器 只要 js/apps/keycloak-server/server/ 存在就复用缓存;只有首次或执行 pnpm delete-server 后才下载
混淆 delete-server 与 delete-data 前者删除整个发行包(触发重新下载),后者仅清空数据(保留发行包)
直接访问 5173/5174 想看到完整控制台 Vite dev server 只提供前端资源,完整页面应通过 Keycloak 的 8080 端口访问(由 Keycloak 反向代理到 Vite)
改完 Java/Quarkus 侧代码仍复用 Nightly 应使用 pnpm start --local 指向本地构建的 keycloak-999.0.0-SNAPSHOT.tar.gz
以为 --admin-dev/--account-dev 有什么魔法 它们底层只是替你设置了 KC_ADMIN_VITE_URL / KC_ACCOUNT_VITE_URL,手动设置环境变量效果完全一致

小结:keycloak-server 是一个为 Keycloak 仓库前端开发量身定制、但完全通用的本地开发服务器启动器。其价值集中在三点——自动化的 Nightly 发行包获取与缓存复用、对 Vite 前端(admin/account 两个控制台)开箱即用的代理联调环境变量注入、以及把一切其余参数让渡给底层 kc start-dev 的透传设计。理解 scripts/start-server.js 的执行路径后,你可以随时判断"该 delete-server 还是 delete-data""该用 Nightly 还是 --local",从而让前后端联调始终处于干净、可复现的状态。

登录后查看全文
keycloak