强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

curl 深度教程 / 第 06 章:认证机制

第 06 章:认证机制

认证(Authentication)是 API 安全的第一道防线。curl 支持几乎所有主流的 HTTP 认证方案,从简单的 Basic Auth 到复杂的 OAuth2 流程。


6.1 认证方案概览

认证方案安全性复杂度curl 选项适用场景
Basic低(Base64 编码)★☆☆☆☆-u user:pass内部服务、开发环境
Bearer Token★★☆☆☆-H "Authorization: Bearer ..."JWT/OAuth2
Digest★★☆☆☆--digest -u user:pass旧系统兼容
API Key★☆☆☆☆-H "X-API-Key: ..."公开 API
OAuth2★★★★☆多步骤流程第三方授权
客户端证书 (mTLS)★★★☆☆--cert / --key企业级安全
NTLM中高★★★☆☆--ntlm -u user:passWindows 域环境
Kerberos (SPNEGO)★★★★☆--negotiate -u :企业 SSO
AWS Signature★★★☆☆自定义头部签名AWS API
Hawk中高★★★☆☆自定义头部签名Web API

6.2 Basic Authentication

Basic Auth 是最简单的认证方式,将 username:password 进行 Base64 编码后放入 Authorization 头。

基本用法

# 使用 -u 选项(推荐)
curl -u admin:secret123 https://api.example.com/admin

# 等价于手动设置 Authorization 头
# Base64("admin:secret123") = "YWRtaW46c2VjcmV0MTIz"
curl -H "Authorization: Basic YWRtaW46c2VjcmV0MTIz" \
  https://api.example.com/admin

# 仅指定用户名(curl 会交互式提示输入密码)
curl -u admin https://api.example.com/admin

# 密码中包含特殊字符
curl -u 'admin:p@ss:word/123' https://api.example.com/admin
# 或使用转义
curl -u admin:p@ss\:word/123 https://api.example.com/admin

# 使用 .netrc 文件(避免命令行暴露密码)
curl --netrc https://api.example.com/admin

.netrc 文件

# ~/.netrc 文件格式
# machine <主机名> login <用户名> password <密码>
machine api.example.com
  login admin
  password secret123

machine ftp.example.com
  login ftpuser
  password ftppass

# 使用 .netrc
curl --netrc https://api.example.com/admin

# 指定 .netrc 文件路径
curl --netrc-file /path/to/.netrc https://api.example.com/admin

# 权限设置(重要!)
chmod 600 ~/.netrc

⚠️ 安全警告:Basic Auth 仅是 Base64 编码,不是加密!必须配合 HTTPS 使用。


6.3 Bearer Token

Bearer Token 是当前最流行的 API 认证方式,广泛用于 JWT(JSON Web Token)和 OAuth2。

基本用法

# 使用 -H 设置 Bearer Token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -H "Authorization: Bearer $TOKEN" \
  https://api.example.com/protected

# 获取 Token 后访问 API
# 1. 获取 Token
TOKEN=$(curl -s -X POST https://auth.example.com/token \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "secret"}' \
  | jq -r '.access_token')

# 2. 使用 Token 访问 API
curl -H "Authorization: Bearer $TOKEN" \
  https://api.example.com/users

# 检查 Token 是否有效
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $TOKEN" \
  https://api.example.com/verify
# 200 → 有效, 401 → 过期/无效

JWT Token 解码

# 解码 JWT Token(查看 Payload)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .

# 检查 Token 过期时间
EXPIRY=$(echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq -r '.exp')
NOW=$(date +%s)
if [ "$EXPIRY" -lt "$NOW" ]; then
  echo "Token 已过期"
fi

6.4 Digest Authentication

Digest Auth 比 Basic Auth 更安全,它使用挑战-响应机制,密码不直接传输。

基本用法

# 使用摘要认证
curl --digest -u admin:secret123 https://api.example.com/admin

# curl 会自动处理挑战-响应流程:
# 1. 服务器返回 401 和 WWW-Authenticate: Digest 头
# 2. curl 计算摘要并重新发送请求
# 3. 服务器验证摘要并返回资源

# 强制使用 Digest(不允许回退到 Basic)
curl --digest --anyauth -u admin:secret123 https://api.example.com/admin

Digest 认证流程

客户端                          服务器
  |                                |
  |--- GET /admin ---------------->|
  |                                |
  |<-- 401 Unauthorized ----------|
  |    WWW-Authenticate: Digest    |
  |    realm="example",            |
  |    nonce="abc123"              |
  |                                |
  |--- GET /admin ---------------->|
  |    Authorization: Digest       |
  |    username="admin",           |
  |    response="哈希值"           |
  |                                |
  |<-- 200 OK --------------------|

6.5 OAuth2 流程

OAuth2 是第三方应用获取用户授权的标准协议。curl 可以手动实现各种 OAuth2 流程。

Authorization Code Flow(授权码流程)

# 1. 用户在浏览器中授权
# 打开以下 URL:
echo "请在浏览器中访问:"
echo "https://auth.example.com/authorize?\
client_id=YOUR_CLIENT_ID&\
redirect_uri=https://callback.example.com&\
response_type=code&\
scope=read+write"

# 2. 用户授权后,从回调 URL 获取授权码
AUTH_CODE="abc123code"  # 从回调 URL 的 code 参数获取

# 3. 用授权码换取 Access Token
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=$AUTH_CODE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=https://callback.example.com")

# 4. 提取 Access Token
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
REFRESH_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.refresh_token')

# 5. 使用 Access Token 访问 API
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://api.example.com/userinfo

Client Credentials Flow(客户端凭证流程)

# 适用于服务间通信(无用户参与)
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=SERVICE_CLIENT_ID" \
  -d "client_secret=SERVICE_CLIENT_SECRET" \
  -d "scope=api.read")

ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')

Refresh Token Flow

# 使用 Refresh Token 获取新的 Access Token
NEW_TOKEN=$(curl -s -X POST https://auth.example.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=$REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET")

ACCESS_TOKEN=$(echo "$NEW_TOKEN" | jq -r '.access_token')
REFRESH_TOKEN=$(echo "$NEW_TOKEN" | jq -r '.refresh_token')

Password Grant(密码模式,已废弃但仍常见)

# 仅适用于高度信任的第一方应用
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "[email protected]" \
  -d "password=userpassword" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=read+write")

6.6 客户端证书认证(mTLS)

客户端证书(Mutual TLS, mTLS)要求客户端也提供证书,实现双向认证。

基本用法

# 使用客户端证书和私钥
curl --cert client.crt --key client.key \
  https://api.example.com/secure

# 使用 PEM 格式证书(证书和私钥在同一个文件)
curl --cert client.pem https://api.example.com/secure

# 带密码保护的私钥
curl --cert client.crt --key client.key \
  --pass "私钥密码" \
  https://api.example.com/secure

# 使用 PKCS#12 格式证书
curl --cert client.p12 --cert-type P12 \
  https://api.example.com/secure

# 指定 TLS 版本
curl --tlsv1.3 --cert client.crt --key client.key \
  https://api.example.com/secure

证书格式转换

# PKCS#12 转 PEM
openssl pkcs12 -in client.p12 -out client.pem -nodes

# PEM 转 PKCS#12
openssl pkcs12 -export -in client.crt -inkey client.key \
  -out client.p12

# 查看证书信息
openssl x509 -in client.crt -text -noout

# 验证证书链
openssl verify -CAfile ca.crt client.crt

6.7 NTLM 认证

NTLM(NT LAN Manager)是 Windows 域环境中的认证协议。

# NTLM 认证
curl --ntlm -u 'DOMAIN\username:password' \
  https://intranet.example.com/api

# 使用 UPN 格式
curl --ntlm -u '[email protected]:password' \
  https://intranet.example.com/api

# NTLMv2(默认使用最新版本)
curl --ntlm -u 'CORP\zhangsan:password123' \
  https://fileserver.corp.local/documents/report.xlsx

# 仅用户名(交互式输入密码)
curl --ntlm -u 'CORP\zhangsan' \
  https://fileserver.corp.local/api

6.8 Kerberos / SPNEGO 认证

Kerberos 是企业级单点登录(SSO)的标准协议。

# 前提:已通过 kinit 获取 Kerberos 票据
kinit [email protected]

# Negotiate(SPNEGO)认证
curl --negotiate -u : https://api.corp.example.com/data

# 使用 keytab 文件
export KRB5CCNAME=/tmp/krb5cc_user
kinit -k -t /etc/krb5.keytab service/[email protected]
curl --negotiate -u : https://api.corp.example.com/data

# 强制使用 SPNEGO
curl --negotiate -u : --auth-no-challenge \
  https://api.corp.example.com/data

6.9 API Key 认证

API Key 不是 HTTP 标准认证方案,但被广泛使用。

常见传递方式

# 方式 1:通过自定义头部(最常见)
curl -H "X-API-Key: your-api-key-here" \
  https://api.example.com/data

# 方式 2:通过 Authorization 头
curl -H "Authorization: ApiKey your-api-key-here" \
  https://api.example.com/data

# 方式 3:通过查询参数(不推荐,会出现在日志中)
curl "https://api.example.com/data?api_key=your-api-key-here"

# 方式 4:通过 Cookie
curl -b "api_key=your-api-key-here" \
  https://api.example.com/data

# 从环境变量读取 API Key
curl -H "X-API-Key: $MY_API_KEY" https://api.example.com/data

常见 API 平台的认证方式

平台认证方式curl 示例
GitHubBearer Token-H "Authorization: Bearer ghp_..."
GitLabPrivate Token-H "PRIVATE-TOKEN: glpat-..."
StripeBasic Auth-u sk_test_...:
OpenAIBearer Token-H "Authorization: Bearer sk-..."
AWSSignature V4自定义签名头部
Google CloudBearer Token-H "Authorization: Bearer ya29..."
AzureBearer Token-H "Authorization: Bearer eyJ..."
CloudflareAPI Token-H "Authorization: Bearer ..."

6.10 认证方案自动协商

# 使用 --anyauth 让 curl 自动选择最佳认证方案
curl --anyauth -u admin:secret https://api.example.com/admin

# 使用 --anyauth 与 -w 检查实际使用的方案
curl --anyauth -u admin:secret -v https://api.example.com/admin 2>&1 \
  | grep "Authorization:"

# 强制使用特定方案(不协商)
curl --basic -u admin:secret https://api.example.com/admin
curl --digest -u admin:secret https://api.example.com/admin
curl --ntlm -u admin:secret https://api.example.com/admin
curl --negotiate -u : https://api.example.com/admin

注意事项

  1. 永远使用 HTTPS:Basic Auth 的密码只是 Base64 编码,明文传输等于裸奔
  2. Token 过期处理:脚本中应检测 401 响应并自动刷新 Token
  3. 不要在命令行中硬编码密码:使用环境变量、.netrc 或密码管理器
  4. 客户端证书安全:私钥文件权限应设为 600,只有属主可读
  5. API Key 轮换:定期更换 API Key,使用环境变量存储
# 安全地从命令历史中隐藏密码
read -sp "Enter password: " PASS
curl -u "admin:$PASS" https://api.example.com/secure
unset PASS

# 或使用配置文件
curl --config curl.conf https://api.example.com/secure
# curl.conf 内容:--user admin:secret

扩展阅读


📖 下一章第 07 章:POST 数据与上传 — 深入了解表单提交、JSON 上传、文件上传和 multipart 编码。