Apache Reqsign 0.20.7 构建并运行示例应用指南
Apache Reqsign 0.20.7 构建并运行示例应用指南(Rust 请求签名库使用示例):从零创建 Cargo 工程、完整 Cargo.toml、AWS SigV4 签名头生成与发送示例源码、编译运行命令与真实回显(authorization/x-amz-date/x-amz-content-sha256 签名头与 200 OK 响应)。
Apache Reqsign 0.20.7 构建并运行示例应用指南
目标:从零构建并运行一个基于 Apache Reqsign 0.20.7 的最小请求签名应用(Rust 库使用示例)。给出完整 Cargo.toml、示例 Rust 源码、编译与运行命令及真实回显:程序为 AWS S3 请求生成 SigV4 签名头(authorization / x-amz-date / x-amz-content-sha256),并把签名后的请求发送到本地 HTTP 服务验证,返回 200 OK。所有命令与输出均在 Ubuntu 22.04.5 + rustc 1.99.0 环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- Rust 工具链:rustc 1.99.0 / cargo 1.99.0(rustup stable)
- Reqsign 版本:0.20.7(feature:aws-v4,依赖 tokio 1 / reqwest 0.12 / http 1)
- 示例工程目录:
/root/reqsign-demo/ - 本地验证服务:python3 http.server(监听 127.0.0.1:8000,提供
/my-bucket/demo.txt) - 演示账号:root
二、前置条件
-
已按《Apache Reqsign 0.20.7 安装指南》安装 Rust 工具链与系统依赖(pkg-config、libssl-dev),并确认版本:
source "$HOME/.cargo/env" rustc --version cargo --version -
实测回显需为
rustc 1.99.0/cargo 1.99.0(reqsign 0.20.7 要求 ≥ 1.86.0)。
三、工程结构
标准 Cargo 布局,仅一个 Cargo.toml 与一个主文件:
reqsign-demo/
├── Cargo.toml
└── src/main.rs
mkdir -p /root/reqsign-demo/src
四、完整 Cargo.toml
[package]
name = "reqsign-demo"
version = "0.1.0"
edition = "2021"
[dependencies]
reqsign = { version = "0.20.7", features = ["aws-v4"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
reqwest = "0.12"
http = "1"
💡 说明:
reqsign开启aws-v4feature 后提供reqsign::aws模块(AWS SigV4 签名);tokio提供异步运行时;reqwest用于把签名后的请求真实发出;http用于构造请求(签名接口操作的是http::request::Parts)。
五、示例源码
创建 /root/reqsign-demo/src/main.rs,其完成六步:静态凭据提供者 → 组装签名器 → 构造待签名请求 → 执行 SigV4 签名 → 打印签名头 → 发送请求到本地 HTTP 服务验证。
示例源码:
use reqsign::aws::{RequestSigner, StaticCredentialProvider, EMPTY_STRING_SHA256};
use reqsign::{Context, Signer};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1) 静态凭据提供者(演示密钥,非真实 AWS 凭据)
let cred = StaticCredentialProvider::new(
"AKIDEXAMPLE",
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
);
// 2) 上下文 + AWS SigV4 请求签名器(服务 s3 / 区域 us-east-1)
let ctx = Context::new();
let signer = Signer::new(ctx, cred, RequestSigner::new("s3", "us-east-1"));
// 3) 构造待签名请求(指向本地 http.server)
let target = "http://127.0.0.1:8000/my-bucket/demo.txt";
let req = http::Request::get(target)
.header("x-amz-content-sha256", EMPTY_STRING_SHA256)
.body(())
.unwrap();
let (mut parts, _) = req.into_parts();
// 4) 执行 AWS SigV4 签名
signer.sign(&mut parts, None).await?;
// 5) 打印签名后的请求头
println!("== 签名后的请求头 ==");
for name in ["authorization", "x-amz-date", "x-amz-content-sha256"] {
match parts.headers.get(name) {
Some(v) => println!("{}: {}", name, v.to_str()?),
None => println!("{}: <missing>", name),
}
}
// 6) 用签名后的请求头重建 reqwest 请求,发送到本地 http.server 验证
let client = reqwest::Client::new();
let mut builder = client
.request(parts.method.clone(), parts.uri.to_string())
.body(reqwest::Body::from(""));
for (name, value) in &parts.headers {
builder = builder.header(name, value);
}
let resp = client.execute(builder.build()?).await?;
println!("== 本地 http.server 响应 ==");
println!("status: {}", resp.status());
Ok(())
}
💡 实现要点:
- 签名接口
signer.sign(&mut parts, None)操作的是http::request::Parts,成功时只改写其中的uri与headers,方法/版本/扩展保持不变。EMPTY_STRING_SHA256是空字符串的 SHA256(e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855),用于无请求体场景;有请求体时应先计算 body 的 SHA256 再写入x-amz-content-sha256。reqwest::Request没有from_parts构造函数,把签名后的Parts转发时用client.request(method, uri)配合.headers()/.body()重建(实测踩坑记录,见第九节 Q3)。- 演示密钥
AKIDEXAMPLE来自 AWS 官方文档示例,仅用于演示。
六、编译与运行
source "$HOME/.cargo/env"
cd /root/reqsign-demo
# 编译
cargo build
# 运行
cargo run
七、运行结果解读
编译成功(Finished \dev` profile [unoptimized + debuginfo] target(s) in 1.58s`),程序真实输出(退出码 0):
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
Running `target/debug/reqsign-demo`
== 签名后的请求头 ==
authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20261012/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=37962216ce11dc6ee635a8aac517e295cb23b0e6856a687141d085e31901c711
x-amz-date: 20261012T164829Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
== 本地 http.server 响应 ==
status: 200 OK
结果解读:
- authorization 头:AWS SigV4 规范格式。以本次实测值为例:
AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20261012/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=37962216ce11dc6ee635a8aac517e295cb23b0e6856a687141d085e31901c711。其中Credential段依次为 访问密钥ID/签名日期/区域/服务/aws4_request(日期20261012、区域us-east-1、服务s3来自签名器配置);SignedHeaders=host;x-amz-content-sha256;x-amz-date列出参与签名的请求头;Signature为 HMAC-SHA256 派生签名值。 - x-amz-date:签名时间(UTC,格式如
20261012T164829Z,即 年4位月2位日2位 T 时2位分2位秒2位 Z),随运行时刻变化,本次实测为20261012T164829Z。 - x-amz-content-sha256:请求体的 SHA256,空请求体即
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855。 - status: 200 OK:签名后的请求被本地 HTTP 服务正常接收并返回文件内容,说明签名头完整可传输;在真实云服务上,服务端会用相同算法校验签名头,校验通过才会放行请求。
⚠️ 说明:
x-amz-date与Signature每次运行都会因当前时间不同而变化,请以实际输出为准;Credential中的日期段与x-amz-date日期段保持一致即说明签名过程正确。
八、注意事项
⚠️ 注意:
- 必须使用 rustup 安装的 Rust 工具链(≥ 1.86.0);apt 版 cargo 1.75.0 无法编译(见第九节 Q1)。
- 签名前必须保证请求 URI 已是规范形态(含 authority),reqsign 不会代为做通用 URI 编码;路径/查询中属于数据的字节需自行百分号编码。
- 静态凭据只适合演示/测试;生产建议使用
DefaultCredentialProvider(从环境变量、~/.aws/credentials等自动加载,详见《配置参数详解》篇)。- 无请求体请求必须携带
x-amz-content-sha256: EMPTY_STRING_SHA256,否则签名与服务端校验会不一致。
九、常见问题
Q1:编译报 feature edition2024 is required?
apt 版 cargo 1.75.0 不支持新版依赖的 edition2024。用 source "$HOME/.cargo/env" 切换到 rustup 工具链(实测 1.99.0)后重跑 cargo build。
Q2:运行报凭据错误 / 签名失败?
确认凭据提供者已正确配置:StaticCredentialProvider::new(access_key, secret_key) 的两个参数不能为空;使用环境变量凭据时须设置 AWS_ACCESS_KEY_ID 与 AWS_SECRET_ACCESS_KEY。
Q3:reqwest::Request::from_parts 不存在 / uri 无法传入 client.request?
reqwest 0.12 的 Request 没有 from_parts 构造函数;client.request(method, url) 的 url 参数支持 String(IntoUrl),把 http::Uri 转成字符串传入,再逐个 .header() 拷贝签名头后 .build()。
Q4:签名后的请求发送到真实云服务返回 403?
常见原因:服务器时间偏差过大(签名时间校验失败)、凭据无权限、区域/服务名与资源不符。先核对 x-amz-date 是否为 UTC 当前时间,再核对 RequestSigner::new(service, region) 与目标服务一致。
十、参考链接
- Reqsign 官方文档:
https://docs.rs/reqsign - crates.io:
https://crates.io/crates/reqsign - AWS SigV4 签名规范:
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html - 源码仓库:
https://github.com/apache/opendal-reqsign