Homepage 集成 UniFi Controller 服务 Widget:配置、认证与状态展示实战指南
2026/9/10 11:43:35 网站建设 项目流程

Homepage 集成 UniFi Controller 服务 Widget:配置、认证与状态展示实战指南

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

Homepage 是一个高度可定制的主页/应用仪表盘项目,支持通过服务 API 集成展示各类应用的实时状态。其中 UniFi Controller 服务 Widget 允许你在仪表盘上直接展示 UniFi Network Controller 的通用连接状态——包括网关在线时长(uptime)、WAN/LAN/WLAN 三个子系统的连通性、在线用户数与已接入设备数。本文将基于仓库中的官方文档 unifi-controller.md 及 unifi 模块源码 展开,从配置写法、认证机制、显示逻辑到故障排查,完整讲解该 Widget 的接入与底层原理,读完即可在自己的 Homepage 上正确接入 UniFi Controller。

Widget 能展示什么

该 Widget 读取 UniFi Network Controller 的站点(Site)健康数据,并将其中的关键指标渲染为若干状态块(Block):

  • uptime:网关系统运行时长(以天为单位,保留一位小数);
  • wan:WAN 子系统连通状态(up / down);
  • lan:LAN 子系统连通状态(up / down);
  • lan_users / lan_devices:LAN 在线用户数与已接入设备数;
  • wlan / wlan_users / wlan_devices:WLAN 对应指标。

Allowed fields: ["uptime", "wan", "lan", "lan_users", "lan_devices", "wlan", "wlan_users", "wlan_devices"](最多展示四个)。注意:设备不支持的字段将不会显示——例如纯交换机或未启用无线网络的设备,WLAN 相关字段会被自动隐藏(详见下文渲染逻辑)。这也意味着最终实际展示的字段组合会随设备型号动态变化。

前置要求

在配置前务必注意官方文档中的警告:

认证时请使用至少具有读取权限的本地账号(local account with at least read privileges)。

不要使用云端 Ubiquiti 账号,而是使用 UniFi 控制器中创建的本地管理员/只读账号,以保证 API 认证与数据读取的可靠性。

配置方法

UniFi Controller 服务 Widget 的配置写在 Homepage 的services.yaml中(默认配置骨架见 src/skeleton/services.yaml)。在目标服务条目下的widget:中声明:

widget: type: unifi url: https://unifi.host.or.ip:port site: Site Name # optional username: user password: pass key: unifiapikey # required if using API key instead of username/password

各参数说明如下:

参数是否必填说明
type必填固定为unifi
url必填UniFi Controller 的地址,格式https://unifi.host.or.ip:port,注意保留端口
site可选站点名称;不填时自动使用控制器的默认站点(default site)
username/passwordkey二选一本地账号的用户名密码
key与用户名密码二选一UniFi API Key,使用 API Key 认证时必须提供,此时不再需要用户名密码

从配置解析看,site参数在 service-helpers.js 中被单独提取并注入 widget 对象:if (type === "unifi") { if (site) widget.site = site; }。也就是说site是 unifi 类型独有的可选参数。

另外值得说明的是安全处理:usernamepasswordkeyapiKey属于私有选项,在 widget-helpers.js 的cleanWidgetGroups中会被从发送到前端的配置中剔除,url也会被删除(仅searchglances类型保留),确保凭据不会泄露到浏览器端。

使用 Info Widget(信息栏)形式

除了挂载在服务条目下,UniFi 状态也可以作为独立的info widget使用,配置在widgets.yaml中(见 docs/widgets/info/unifi_controller.md):

- unifi_console: url: https://unifi.host.or.ip:port site: Site Name # optional username: user password: pass key: unifiapikey # required if using API key instead of username/password

两者的区别在于挂载位置(服务条目 vs. 顶部信息栏),底层数据源与认证逻辑完全一致。在 proxy.js 中可以看到,代理处理器会区分两种场景:当请求的groupservice均为unifi_console时,走 info widget 分支,通过getPrivateWidgetOptions("unifi_console", index)读取私有配置;否则走常规服务 widget 分支,通过getServiceWidget(group, service, index)解析服务配置。

底层实现原理

1. API 定义与数据端点

widget 的 API 模板定义在 widget.js:

const widget = { api: "{url}{prefix}/api/{endpoint}", proxyHandler: unifiProxyHandler, mappings: { "stat/sites": { endpoint: "stat/sites" }, }, };

即前端通过stat/sites端点(最终请求{url}{prefix}/api/stat/sites)获取所有站点的健康数据。{prefix}会根据设备类型动态决定(见下文),这是为了兼容 UDM Pro / UDM SE 等内置控制器(UDMP)与独立控制器之间 API 路径的差异。

2. 认证流程与缓存机制

认证是这套 Widget 最复杂的部分,实现在 utils/proxy/handlers/unifi.js 与 proxy.js 中,整体流程如下:

  1. 前缀探测:当没有缓存的 prefix 时,代理先向widget.url发起一次探测请求,读取响应头:
    • 若存在x-csrf-tokenaccess-control-expose-headers相关头,则判定为 UDMP 设备,prefix = "/proxy/network",并捕获 CSRF Token;
    • 否则为传统独立控制器,prefix为空字符串。
  2. API Key 快捷认证:若配置了key,则直接以X-API-KEY: <key>请求头调用 API(Accept: application/json),无需登录流程。这也是文档要求“使用 API Key 时无需用户名密码”的源码依据(proxy.js)。
  3. 会话登录:未配置 API Key 时,代理会带上 cookie 与 CSRF Token 先请求 API;若返回401,则自动向登录端点 POST 用户名密码(请求体包含usernamepasswordremember: truerememberMe: true,见 handlers/unifi.js)。
  4. 登录校验:登录响应需满足meta.rc === "ok"或包含login_time/update_time字段才视为成功(isSuccessfulLoginResponse),随后将 cookie 写入 cookie-jar 并重放数据请求。
  5. prefix 缓存:探测出的 prefix 会以unifiProxyHandler__prefix.<service>为键缓存在内存中(memory-cache),避免每次请求都重复探测;登录成功后 cookie 同样由 cookie-jar.js 管理。这也正是“凭据错误后需要重启服务/重建容器清缓存”的原因——prefix 与 cookie 均缓存在服务端内存中。

3. 前端渲染逻辑

component.jsx 负责把stat/sites数据渲染成状态块:

  • 站点选择:若配置了site,按desc(站点描述)匹配;否则取name === "default"的默认站点。若配置的站点找不到,会渲染错误Site '<site>' not found(对应测试用例见 component.test.jsx)。
  • 数据解析:从defaultSite.health中分别取出wanlanwlan三个子系统的健康项;status === "ok"视为 up,status === "unknown"的子系统会被隐藏(show = false)——这就是“设备不支持的字段不显示”的实现方式。
  • uptime 计算:读取wan["gw_system-stats"].uptime(单位秒),除以 86400 换算为天,保留一位小数后拼接unifi.days本地化后缀(component.jsx)。
  • 字段互斥显示:当lanwlan同时可用时,只显示各自的用户数(lan_users/wlan_users);当只有一个子系统可用时,才额外补充显示该子系统的设备数(lan_devices/wlan_devices)与连通状态,确保总块数不超过四个。
  • 空数据兜底:若所有子系统都不可见且无 uptime,则显示unifi.empty_data占位块。

上述行为均有对应的 Vitest 测试覆盖,例如默认站点数据存在时渲染 uptime、WAN 状态与用户数的用例(component.test.jsx),可以作为理解渲染规则的参考。

常见问题排查

1. 输入正确凭据后仍报 "API Error"

官方文档给出了明确提示:如果输入了例如错误的凭据并收到 "API Error",可能需要重建容器或重启服务以清除缓存。这是因为登录失败后,服务端内存中的 prefix/cookie 缓存可能处于不一致状态(见上文“缓存机制”)。

2. 提示 "Site 'xxx' not found"

site参数必须与控制器中站点的desc字段精确匹配。如果拿不准站点名称,可以省略site参数让 Widget 自动使用默认站点。

3. 某些字段不显示

属于正常现象:lan_deviceslanwlan_deviceswlan等字段仅在对应子系统存在且状态不是unknown时展示;设备不支持的子系统会被自动隐藏。

4. 认证失败

确认使用的是具有读取权限的本地账号,并检查url是否包含正确的端口(默认https://<host>:8443或 UDM 系列的其他端口)。

小结

UniFi Controller 服务 Widget 是 Homepage 中认证逻辑较为完整的一类集成:它同时支持用户名密码会话登录与 API Key 直连两种模式,能自动适配 UDMP 与独立控制器两种 API 路径,并依据设备实际能力动态渲染最多四个状态字段。配置只需在services.yaml的服务条目下声明type: unifi及对应凭据即可。如需深入了解实现细节,可继续阅读 unifi/widget.js、unifi/proxy.js、unifi/component.jsx 及通用认证处理器 utils/proxy/handlers/unifi.js。

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询