如何生成 Basic Auth 请求头
- 输入 用户名 和 密码。
- 字符集 保持 UTF-8,除非服务器是需要 ISO-8859-1(Latin-1)的旧服务器。
- 用 复制请求头 复制完整的
Authorization: Basic …一行,或用 仅复制令牌 只复制 Base64 部分。 - 在 现成代码 中,把 URL 设为你的接口地址,然后复制对应客户端的代码片段。互换 会把请求头发送到解码器,方便再次核对。
请求头里有什么
Basic 认证由 RFC 7617 定义。客户端用冒号连接这两个值,对字节做 Base64 编码,然后放在一个请求头中发送:
| 用户名 | 密码 | 请求头的值 |
|---|---|---|
Aladdin | open sesame | Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
deploy | hunter2 | Basic ZGVwbG95Omh1bnRlcjI= |
josé | pässwörd | Basic am9zw6k6cMOkc3N3w7ZyZA==(UTF-8) |
josé | pässwörd | Basic am9z6Tpw5HNzd/ZyZA==(Latin-1) |
最后两行说明了字符集为什么重要:同样的文本会产生不同的字节,因此期望另一种编码的服务器看到的是错误的密码。需要 UTF-8 的服务器可以在质询中说明:WWW-Authenticate: Basic realm="api", charset="UTF-8"。
这里的 Base64 只是一种传输格式。任何人复制了这个请求头,都可以用 Basic Auth 解码器 把它还原成密码,这就是 Basic 认证只能用在 HTTPS 上的原因。Base64 不是加密 对此有更详细的说明。
工具会警告哪些字符
- 用户名中的冒号。 RFC 7617 禁止这样做。服务器在第一个冒号处分割,用户名的一部分会被当成密码。
- 控制字符,例如制表符或换行符,Basic 凭据中不允许出现。
- 选择 Latin-1 时 Latin-1 中没有的字符,例如 Emoji 或西里尔字母。它们会被替换为
?,这绝不是你想要的结果。 - UTF-8 下的非 ASCII 字符。 符合 RFC,但旧服务器可能会以不同方式读取,请先测试。
密码中可以有冒号,因为只有第一个冒号用于分隔这两个值。
在代码中发送 Basic 认证
工具中的代码片段会使用你填写的值生成,并针对每种语言做了安全的引号处理。最简单的版本如下:
curl -u 'deploy:hunter2' https://api.example.com/
import requests
r = requests.get("https://api.example.com/",
auth=("deploy".encode("utf-8"), "hunter2".encode("utf-8")))
Python 示例特意传入字节。requests 收到 str 值时会按 Latin-1 编码,所以含有 € 或 ł 的密码会失败;传入字节则能确保发送的正是你选择的 UTF-8。
在浏览器 JavaScript 中,请自己构造请求头:fetch 会拒绝带有 user:pass@ 的 URL,而 btoa() 遇到 Latin-1 以外的字符会抛出异常,因此要先把字符串编码为 UTF-8 字节,再做 Base64。生成的 fetch 代码片段直接嵌入了编码好的令牌,从而避开了这两个问题。JavaScript Base64 指南 讲解了 UTF-8 这一步,Node.js 页面则展示了 Buffer 版本。
请求仍然返回 401 时
先检查响应中的 WWW-Authenticate 请求头。如果它写的是 Bearer,说明 API 需要令牌,永远不会接受 Basic 凭据。如果写的是 Basic,就解码你实际发送的请求头(用 curl -v 时它会显示为 > Authorization: Basic …),并与预期的值进行比较;从密码管理器复制时带上的多余空格或末尾换行符是常见的罪魁祸首。代理使用自己的请求头 Proxy-Authorization,格式相同。
常见问题
Basic 认证请求头是怎么构造的?
用冒号连接用户名和密码,把这个字符串编码为 UTF-8 字节,对字节做 Base64 编码,再在前面加上 Basic 。Aladdin 和 open sesame 得到 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==。
Basic 认证安全吗?
只有在 HTTPS 下才安全。Base64 什么也隐藏不了,任何能看到请求的人都能在一秒内解码出密码。通过 TLS 传输时,请求头会和请求的其他部分一起被加密。
密码里可以有冒号吗?
可以。服务器在第一个冒号处分割,所以它之后的所有内容都属于密码。不能包含冒号的是用户名。
为什么含非 ASCII 字符的密码在某些服务器上会失败?
RFC 7617 允许服务器要求使用 UTF-8,但旧服务器会按 ISO-8859-1 解码请求头。test:123£ 在 UTF-8 中是 dGVzdDoxMjPCow==,在 Latin-1 中是 dGVzdDoxMjOj。试试另一种 字符集,或者只使用 ASCII。