博客

Home Assistant 长期访问令牌:如何创建、为什么必须是管理员,以及“能连接却什么都不显示”

长期访问令牌是应用或脚本无需密码即可登录 Home Assistant 的方式。本文介绍它在哪里、如何创建一个第一次就能用的令牌,以及为什么“已连接却是空的”几乎总是意味着创建令牌的用户不对。

发布于 阅读约 16 分钟

本文目录
  1. 简短回答
  2. 什么是长期访问令牌
  3. 在哪里找到它
    1. “我找不到”
  4. 创建并复制
  5. 为什么有些应用需要管理员的令牌
    1. 给应用管理员权限是个好主意吗?
  6. “能连接却什么都不显示”:/api/template 返回的 401
    1. Home Assistant 会显示什么
    2. AmazHA 如何发现它、如何提示
    3. 如何确认一个用户是不是管理员
  7. 用 curl 自己检查
    1. “Local access only”导致的 401
  8. 粘贴问题
    1. AmazHA 会清理什么、拒绝什么
  9. 保管好它
  10. 在 AmazHA 中
    1. 一个令牌,两个地址
    2. 令牌去哪里,不去哪里
    3. 当 AmazHA 提示令牌有问题时
  11. 常见问题

简短回答

长期访问令牌是给应用和脚本用的密码替代品:你在 Home Assistant 用户资料的安全选项卡中、长期访问令牌下创建它,Home Assistant 只会显示一次。它的有效期是 10 年。有些应用需要管理员创建的令牌,因为 API 的某些部分(例如 /api/template)会以 401 拒绝其他所有用户。

本文接下来逐一讲解:令牌是什么、在哪里找到、如何复制而不弄坏它、为什么管理员这个问题很重要、如何用两条 curl 命令测试令牌,以及如何管好你的令牌。示例用的是 AmazHA,一款面向 Amazfit 手表的 Home Assistant 应用,因为它把这些点全都碰到了:它需要令牌,需要管理员的令牌,还得应对复制粘贴时被弄坏的令牌。

什么是长期访问令牌

长期访问令牌是一种凭据,让程序无需经过登录界面,就能以你的 Home Assistant 用户身份执行操作。当你登录网页界面时,Home Assistant 会给你的浏览器一个短期访问令牌(30 分钟)和一个用来续期的刷新令牌。脚本、手机应用或手表应用很难走完这套登录流程,所以 Home Assistant 提供了第二种令牌:由你手动创建、复制一次,然后交给程序。

实际使用中,有三个特性很重要:

  • 它的有效期是 10 年。 Home Assistant 自己的身份验证 API 文档写明长期令牌“有效期为 10 年”,用户资料页面也重复了这一点:每个令牌自创建起 10 年内有效。
  • 它只显示一次。 Home Assistant 不保存令牌本身,所以无法再次显示。如果弄丢了,就新建一个。
  • 它就是创建它的那个用户。 令牌带有创建它的用户的权限,不多也不少。管理员创建的令牌,在它签署的每个请求中都是管理员;普通用户创建的令牌,就是普通用户。

令牌放在每个请求的 HTTP 标头中传送:

Authorization: Bearer <your token>

客户端要做的只有这些。没有用户名、没有密码、也没有会话:凡是在这个标头中带有有效令牌的请求,都会被当作该用户接受。

在哪里找到它

长期访问令牌在你自己的用户资料中、安全选项卡里创建。在 Home Assistant 应用或浏览器中:

  1. 打开侧边栏(手机上是 ≡ 菜单),点按底部你的名字。
  2. 在用户资料中,打开安全选项卡。
  3. 在这个选项卡靠下的位置,就是长期访问令牌部分,里面列出你已有的令牌,还有一个创建令牌按钮。

Home Assistant 的用户文档也是这样说的:用户资料 › 安全,你在这个页面上还可以修改密码、设置多因素身份验证以及管理刷新令牌。

“我找不到”

最常见的原因是选项卡。用户资料打开时显示的是常规设置(语言、主题等);令牌部分在安全选项卡里。许多旧教程说要滚动到用户资料页面的底部,那在用户资料分成选项卡之前是对的。

另外两个原因:

  • 你在找别人的令牌。 每个用户只能看到和管理自己的令牌。家里其他人创建的令牌不会出现在你的用户资料中,你也无法在那里删除它。
  • 你登录的用户和你以为的不一样。 看看侧边栏底部的名字。如果某个应用需要管理员的令牌(下文详述),请在创建之前确认这个名字属于管理员。

创建并复制

创建令牌只需点按四下;容易出错的是复制。步骤如下:

  1. 在安全选项卡的长期访问令牌下,点按创建令牌。
  2. Home Assistant 会让你给令牌起个名字。用应用的名字,例如 AmazHA。名字在你的令牌中必须唯一。
  3. 接下来的对话框会显示令牌,并提示“复制你的访问令牌。它不会再显示。”现在就复制,完整地复制。
  4. 关闭对话框。令牌现在以它的名字出现在列表中,并附有创建日期。

令牌是一长串字母、数字、- 和 _,由点分成三段。正是它的长度导致了大多数复制问题:它在一行里放不下,随手一选就只选中了一部分;还有些应用会在屏幕上用省略号(…)缩短长字符串,然后复制的就是它显示的那部分。

一些能避免麻烦的好习惯:

  • 使用对话框里的复制按钮,而不是手动选择。
  • 直接粘贴到需要它的应用中。经过聊天、电子邮件或笔记应用中转,可能会混入不可见字符、排版引号或换行。
  • 不要在前面加 Bearer ,除非应用明确要求填写整个标头。几乎所有应用都会自己加上这个词。
  • 如果在另一台设备上也需要,就在那里再创建一个令牌,而不是把第一个四处传送。

为什么有些应用需要管理员的令牌

有些应用需要管理员的令牌,是因为 Home Assistant 把少数几个 API 端点保留给管理员,而令牌只能做它的用户能做的事。最清楚的例子是模板端点 POST /api/template,它在服务器上渲染一个 Jinja 模板并返回结果。

在 Home Assistant 的源代码中,提供这个端点的视图是 homeassistant/components/api/__init__.py 里的 APITemplateView,它的 post 方法带有 @require_admin 装饰器。这个装饰器会检查令牌背后的用户;如果该用户不是管理员,就会抛出 Unauthorized,Home Assistant 的 HTTP 层再把它变成 401 Unauthorized。REST API 文档也把这个端点标注为“Admin”。

它并不是唯一一个。REST API 大致可以这样划分:

端点 普通用户的令牌 管理员的令牌
GET /api/(API 是否在运行?) 可以 可以
GET /api/states、GET /api/states/<entity_id> 可以 可以
POST /api/services/<domain>/<service>(开关设备) 可以 可以
GET /api/camera_proxy/<entity_id> 可以 可以
POST /api/template 不可以:401 可以
POST 或 DELETE /api/states/<entity_id>(直接写入状态) 不可以 可以
POST /api/events/<event_type> 不可以 可以
GET /api/error_log 不可以 可以

那么,应用为什么会需要模板端点呢?因为有些信息不在普通的 REST 端点里。最明显的是区域:/api/states 会返回每个实体及其状态和属性,但不包括它所属的区域,而 REST API 也没有列出区域的端点。模板却可以查询:area_id(entity_id) 和 area_name(...) 会返回 Home Assistant 为每个实体解析出的区域,依据是实体自身的设置或其所属设备的设置。一个想像 Home Assistant 仪表盘那样按房间展示你的家的应用,因此要渲染模板,也就需要管理员来做这件事。

给应用管理员权限是个好主意吗?

Home Assistant 自己的安全建议是:只给确实需要的账户管理员权限。需要 /api/template 的应用正属于这种情况,你有两种合理的处理方式:

  • 用你自己的管理员用户创建令牌。 最简单的做法。令牌以它的名字列在你的用户资料下,删除它就只会吊销这一个应用。
  • 在设置 › 人员中为这个应用单独创建一个管理员用户,以该用户身份登录一次,在那里创建令牌。它的“最后使用”信息与你的分开,以后也可以整个停用这个用户。只要应用还在使用,就让它保持启用:被停用用户的令牌会失效。如果应用还要从家庭以外连接,就不要勾选 Local access only(仅限本地访问),原因见下文的 401 一节。

无论哪种方式,都应该像对待密码一样对待这个令牌:管理员的令牌能做你在 Home Assistant 中能做的一切。

“能连接却什么都不显示”:/api/template 返回的 401

当一个应用连接成功却什么都不显示时,原因几乎总是令牌来自一个不是管理员的用户。连接测试能通过,因为大多数应用用 GET /api/ 来测试,而这个端点接受任何有效令牌。状态也能读取。只有模板请求失败,返回 401,而一个靠这个模板构建设备列表的应用,最后就没有任何东西可显示。

从应用一侧看,过程是这样的:

  1. 用令牌请求 GET /api/:200,{"message": "API running."}。应用报告“已连接”。
  2. GET /api/states/...:200。状态都在。
  3. POST /api/template,把实体映射到区域:401。没有区域,就没有房间,于是屏幕是空的。

让人困惑的是,其他一切看起来都没问题。地址正确,令牌有效,Home Assistant 也在运行。甚至操作都能成功:POST /api/services/... 对普通用户开放,所以用同一个令牌,仍然能在应用里开关一盏灯。

Home Assistant 会显示什么

Home Assistant 把它发出的每一个 401 都算作一次登录失败,包括管理员检查产生的那个。它的日志里会出现一条以“Login attempt or request with invalid authentication from …”开头的警告,写明请求来自哪个地址(在家时通常是你的手机或你的服务器),网页界面还会显示一条 Login attempt failed(登录尝试失败)通知。如果你开启了 IP 封禁并设置了封禁前允许的登录尝试次数,这类 401 积累到一定数量就会封禁该地址:此后它的所有请求都会得到 403 Forbidden,直到你把它从 ip_bans.yaml 中删除并重启 Home Assistant。

所以,如果你反复看到指向你自己手机的“Login attempt failed”通知,除了令牌已被删除之外,另一种解释就是:某个应用正用普通用户的令牌调用仅限管理员的端点。

AmazHA 如何发现它、如何提示

AmazHA 通过 /api/template 读取你的区域,所以它会专门检查这种情况,而不是让你面对一块空空的手表:

  • 当你点按连接时,手机先用 GET /api/ 检查地址,然后向 /api/template 发送一个最简单的模板 {{ 1 }}。如果这个模板以 401、403 或 400 被拒绝,就判定该令牌不属于管理员。Home Assistant 设置页面随后会显示已连接 ✓,下方有一行琥珀色文字:“已连接,但此令牌没有管理员权限,因此手表无法加载你的实体。请在具有 Administrator 角色的 Home Assistant 用户下创建长期访问令牌,并粘贴到上方。”
  • 在手表上,当区域模板被拒绝、房间无法加载时,主屏幕会显示横幅需要管理员令牌 ·“令牌没有管理员权限 — 请使用 Home Assistant 管理员用户”,而不是笼统的“离线”。
  • 在支持报告中(可从 AmazHA 设置发送),有一行“HA token”会说明令牌是否被识别为管理员的令牌,但绝不会包含令牌本身。

无论哪种情况,解决方法都一样:以管理员身份登录,新建一个长期访问令牌,粘贴进去,再点按一次连接。出问题时怎么办的第 5 步在视频中演示了这一点。

如何确认一个用户是不是管理员

打开设置 › 人员,然后切换到用户选项卡。如果是管理员,组这一列会显示管理员;打开某个用户,可以看到管理员开关(“管理员可以管理用户、设备、自动化和仪表盘。”)。

还有一个更快的检验方法:如果你当前登录的账户的侧边栏里根本没有设置这一项,那这个用户就不是管理员。Home Assistant 把它的配置面板注册为仅限管理员,所以普通用户永远看不到它。这时,请退出登录,以管理员身份登录,再在那里创建令牌。

用 curl 自己检查

在同一网络中的电脑上,用两条 curl 命令,一分钟就能测试任何令牌:一条请求 /api/,任何有效令牌都能通过;另一条请求 /api/template,只有管理员的令牌能通过。示例中使用 192.168.1.50:8123 作为 Home Assistant 的地址,请换成你自己的。在 macOS 或 Linux 终端中可以直接运行。

为了不让令牌留在 shell 历史记录中,先把它读入一个变量。命令等待输入时粘贴令牌,然后按回车:

read -rs HA_TOKEN

测试 1:令牌是否有效?

curl -s -w "\nHTTP %{http_code}\n" \
  -H "Authorization: Bearer $HA_TOKEN" \
  http://192.168.1.50:8123/api/

有效的令牌会得到 {"message":"API running."} 和 HTTP 200。注意末尾的斜杠:端点是 /api/,不是 /api。

测试 2:令牌是否属于管理员?

curl -s -w "\nHTTP %{http_code}\n" -X POST \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template": "{{ 1 }}"}' \
  http://192.168.1.50:8123/api/template

管理员的令牌会得到渲染后的模板 1 和 HTTP 200。普通用户的令牌会得到 HTTP 401。

如何把两个结果放在一起解读:

测试 1(/api/) 测试 2(/api/template) 含义 怎么做
200 200 有效的管理员令牌 令牌没问题,去别处找原因
200 401 普通用户的有效令牌 以管理员身份新建一个令牌
401 401 令牌无效:已删除、被截断、用户已停用,或 Local access only 用户从外部访问 新建一个令牌,完整复制
403 403 你测试时所用的地址已被封禁 将其从 ip_bans.yaml 中删除,重启 Home Assistant
404 或一个网页 (任意) 该地址不是 API:端口后面多了路径,或者是另一台服务器 只填服务器地址,后面不要加任何内容
无响应 无响应 地址错误,或者从你所在的位置无法访问 先检查地址和网络

有两点需要注意。第一,这是在你的电脑上测试令牌;手机上的应用访问 Home Assistant 的路径可能不同,尤其是在离家时。第二,对于需要区域的应用来说,仅仅通过测试 1 几乎说明不了什么:普通用户的令牌恰恰能通过这一项测试。

“Local access only”导致的 401

开启了 Local access only(仅限本地访问)的用户只能从你的局域网登录,Home Assistant 对该用户的令牌也执行同样的规则。来自你网络之外的地址的请求,或者经由 Home Assistant Cloud 到达的请求,都会以 401 被拒绝,尽管同一个令牌在家里完全正常。如果某个应用在你的 Wi-Fi 上能用,离家后却返回 401,在怀疑远程地址之前,先到设置 › 人员中打开该用户,看看这个开关。关于远程地址本身,请看 在手表上离家使用 Home Assistant。

粘贴问题

一个看起来没问题的令牌,仍然可能是错的,因为你粘贴的内容并不总是 Home Assistant 给你的内容。Home Assistant 会逐个字符比对令牌,所以多一个或少一个字符,都是无效令牌,都会得到 401。常见的罪魁祸首:

发生了什么 怎么混进来的 后果
不可见字符:零宽空格、不换行空格、字节顺序标记、软连字符 经由聊天、电子邮件或笔记应用复制 请求失败,有时甚至还没离开设备就失败了
令牌两边的排版引号,例如 “…” 或 ‘…’ 会把引号“智能化”的笔记应用或键盘 401
粘贴进来的 Bearer 前缀 从教程中复制了整个示例标头 应用发送的是 Bearer Bearer eyJ…:401
以 … 结尾的被截断的令牌 从把长字符串缩短显示的界面上复制 401,或被手机的 HTTP 组件拒绝
中间有换行 复制了一个折成两行的令牌 401

所有这些问题的解决方法都一样:用对话框的复制按钮重新复制令牌,然后直接粘贴。如果对话框已经关闭,令牌就没了;新建一个,并删除旧的条目。

AmazHA 会清理什么、拒绝什么

AmazHA 会自己处理那些能修正的情况,在你保存令牌时处理一次,在手机读取令牌发起请求时再处理一次:

  • 删除: 令牌中任何位置的空格、换行、零宽字符、不换行空格、字节顺序标记、软连字符和方向标记。这些都不可能是 Home Assistant 令牌的一部分,令牌只由字母、数字、-、_ 和点组成。
  • 从两端去掉: 直引号和排版引号、反引号以及法文引号(« »)。
  • 从开头去掉: 粘贴进来的 Bearer (不论大小写),因为 AmazHA 会自己加上这个词。

清理无法修正的,是令牌中绝不会出现的可见字符,典型的就是复制被截断时留下的 …。AmazHA 不会去猜:它根本不会发送这样的令牌,所以不会有请求到达 Home Assistant,也不会被记作一次登录失败。设置中的 Home Assistant 页面会显示令牌无效,并解释:“令牌中含有 Home Assistant 令牌不可能包含的字符 — 通常是复制时被截断了(…)。请从 Home Assistant 个人资料 › 安全 中重新复制完整令牌,并粘贴到上方。”手表会显示请检查令牌 ·“其中含有无效字符 — 请重新粘贴”。这就是出问题时怎么办的第 6 步。

保管好它

把每个长期令牌都当作一个 10 年内不会过期的密码来对待:一个应用一个令牌,名字要说明是哪个应用,停用那个应用的当天就删除它。具体来说:

  • 一个应用或设备一个令牌。 如果你把同一个令牌给了三个程序,就无法只吊销其中一个而不影响另外两个,也无法分辨是谁在调用。
  • 用应用的名字命名。 例如“AmazHA”“备份脚本”“墙面平板”。以后在列表中你只能看到名字;令牌本身再也不会显示。
  • 时不时看看列表。 每个条目都显示创建时间;使用过之后,还会显示最后一次使用的时间和来源。几个月都没人用过的令牌,可以考虑删除。
  • 通过删除来吊销。 在安全选项卡中,按名称删除令牌。使用它的应用会在下一次请求时失败,返回 401;其他一切都不受影响。
  • 如果令牌可能已经泄露,删除它,再新建一个。删除是吊销单个令牌的唯一方式;把新令牌填进应用只需一分钟。
  • 绝不要把令牌粘贴到支持请求、论坛帖子或截图中。 好的应用的诊断信息从来不需要它。

在同一个选项卡中删除所有刷新令牌,会让你的设备退出登录,但会保留当前会话和你的长期令牌,Home Assistant 的确认对话框也是这样说明的。长期令牌只能逐个吊销。

在 AmazHA 中

AmazHA 只需要一个来自管理员的长期令牌,在 Zepp 应用里的 AmazHA 设置中填写一次;这一个令牌同时适用于本地地址和远程地址,并且只保存在你的手机上。解锁完整版之后才会出现连接字段(一次性解锁,无订阅:见解锁完整版)。然后:

  1. 按上文所述,以管理员身份创建令牌(连接 Home Assistant 的第 1–3 步)。
  2. 在 Zepp 应用中进入我的 › 你的手表 › 应用 › AmazHA › 设置,然后点按 Home Assistant(第 4 步)。
  3. 在本地 URL (LAN) 中填写你在家使用的地址,例如 http://192.168.1.50:8123;如果你希望离家时手表也能用,再在远程 URL 中填写外部地址。两栏中任意一栏都可以留空。
  4. 把令牌粘贴到长期访问令牌中(第 7 步)。
  5. 点按连接。两个地址都已填写时,结果会分别显示 LAN 和远程两项;只填了一个地址时,显示已连接 ✓。如果令牌不属于管理员,下方会出现上文所说的那行琥珀色文字。

一个令牌,两个地址

远程地址不需要第二个令牌。令牌属于用户,而不属于地址:无论请求是经由你的 Wi-Fi 还是从外部到达 Home Assistant,同一个令牌都有效。在家时 AmazHA 使用本地地址;远程地址只在手机离家时使用。唯一的例外是上文提到的 Local access only 用户,按照设计,它的令牌会被外部请求拒绝。

令牌去哪里,不去哪里

手表从不直接与 Home Assistant 通信。是你的手机通过 Zepp 应用来做这件事,令牌也保存在那里,保存在手机上。它只会被发送到你的 Home Assistant 服务器,放在手机自己发出的请求的 Authorization 标头中;它绝不会被发送到手表,手表通过与手机之间的 Bluetooth 连接只接收它要显示的内容。AmazHA 没有自己的服务器可供令牌经过,支持报告也绝不会包含它。

手机用令牌做的事情,逐个请求列出如下:

做什么 Home Assistant 端点 需要管理员?
点按连接时检查地址 GET /api/ 否
检查令牌是否属于管理员 POST /api/template,内容为 {{ 1 }} 是
读取你所选设备的状态 GET /api/states、GET /api/states/<entity_id> 否
把每个设备映射到它的区域,让手表显示房间 POST /api/template 是
开关设备、运行场景 POST /api/services/<domain>/<service> 否
摄像头快照 /api/camera_proxy/<entity_id> 否
注册手表自己的传感器(如果你开启了) POST /api/mobile_app/registrations 否

最后一行是手表传感器功能,它把你 Amazfit 手表的心率、步数、电量等作为 Mobile App 集成的一个设备发送到 Home Assistant:把你的 Amazfit 数据发送到 Home Assistant一文有详细介绍。

当 AmazHA 提示令牌有问题时

在手表上 在 AmazHA 设置中 原因 解决方法
需要管理员令牌 已连接 ✓,下方有琥珀色的管理员提示 令牌属于普通用户 由管理员新建令牌(故障排除第 5 步)
请检查令牌 令牌无效 令牌中有一个正常令牌里不会出现的字符,通常是复制被截断留下的 … 重新完整复制令牌(故障排除第 6 步)
离线 · 无法连接 Home Assistant,代码中提到 401 错误 401(两个地址都已填写时,出错的那个显示为红色) 令牌已被删除、其用户已停用,或被外部请求拒绝 新建一个令牌并粘贴进去
“请打开手机应用,填写 HA 服务器地址和令牌” 请输入 URL 和令牌 还没有保存任何内容 填写地址和令牌,点按连接

离线下方的那行小代码是给技术支持看的:如果你写信过来,一张手表的照片就能准确说明是哪里出了问题。手表可能显示的其他所有提示,请看出问题时怎么办。

常见问题

在 Home Assistant 中哪里可以找到长期访问令牌?

打开你的用户资料(点按侧边栏底部你的名字),切换到安全选项卡。长期访问令牌部分就在这里,还有创建令牌按钮。一些旧教程说“滚动到用户资料页面底部”,那是用户资料还没有分成选项卡时的写法。

为什么找不到长期访问令牌这一部分?

通常是因为你停留在用户资料的第一个选项卡上:这一部分在安全选项卡里。每个用户只能看到和管理自己的令牌,所以在你的用户资料里找不到别的用户创建的令牌。

长期访问令牌的有效期是多久?

从用户资料页面创建的令牌,自创建起有效期为 10 年。退出登录时它不会失效,会一直有效,直到你删除它、该用户被停用,或者 10 年期满。

关闭对话框后还能再看到令牌吗?

不能。Home Assistant 不保存令牌本身,所以无法再次显示。如果弄丢了,删除旧的条目,再创建一个新的。

一个以前能用的令牌,为什么现在返回 401 Unauthorized?

令牌被删除了、用户被停用了,或者令牌没有完整粘贴。开启了 Local access only(仅限本地访问)的用户,在请求来自家庭网络之外或经由 Home Assistant Cloud 时也会收到 401。可以用本文中的 curl 命令测试。

令牌必须由管理员创建吗?

只有那些用到 API 中仅限管理员部分的应用才需要。POST /api/template 就是其中之一:Home Assistant 的代码给它标注了 @require_admin。普通用户的令牌可以读取状态、调用服务,但每个模板请求都会得到 401。

AmazHA 需要管理员令牌吗?

需要。AmazHA 通过模板 API 读取你的区域,而 Home Assistant 只允许管理员使用它。用普通用户的令牌,连接可以成功,但手表无法加载你的房间,AmazHA 会提示需要管理员令牌。详见出问题时怎么办的第 5 步。

如何吊销一个长期访问令牌?

在你的用户资料的安全选项卡中,在长期访问令牌下按名称找到该令牌并删除。使用它的应用会在下一次请求时停止工作,其他一切都不受影响。

观看视频

本文所依据的简短教程:视频为英文讲解,每一步都有中文文字说明。

全部文章