✨ 完成API签名工具的基础结构,包含Cargo配置、README文档及核心库实现,支持多种签名算法和命令行工具功能。
This commit is contained in:
231
rust/README.md
Normal file
231
rust/README.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# API签名工具 - Rust实现
|
||||
|
||||
## 项目结构
|
||||
|
||||
根据实际项目文件结构:
|
||||
|
||||
```plaintext
|
||||
rust/
|
||||
├── Cargo.toml # Cargo配置文件
|
||||
├── Cargo.lock # 依赖锁定文件
|
||||
├── src/
|
||||
│ ├── main.rs # 命令行工具入口
|
||||
│ └── lib.rs # 库入口和核心实现
|
||||
└── target/ # 构建输出目录
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 构建项目
|
||||
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 运行命令行工具
|
||||
|
||||
```bash
|
||||
cargo run --release -- [选项]
|
||||
```
|
||||
|
||||
或使用编译后的二进制文件:
|
||||
|
||||
```bash
|
||||
./target/release/apisign [选项]
|
||||
```
|
||||
|
||||
### 命令行选项
|
||||
|
||||
| 选项 | 描述 |
|
||||
|------|------|
|
||||
| `-a, --algorithm` | 签名算法: md5, sha1, sha256, hmac-sha256 |
|
||||
| `-u, --url` | API基础URL |
|
||||
| `-p, --param` | 请求参数,格式为key=value,可多次使用 |
|
||||
| `-k, --key` | 访问密钥ID |
|
||||
| `-s, --secret` | 密钥 |
|
||||
| `-c, --channel` | 合作渠道方ID |
|
||||
| `-h, --help` | 显示帮助信息 |
|
||||
| `-m, --mode` | 操作模式: sign_url, sign_params, verify |
|
||||
| `-t, --timestamp` | 自定义时间戳 |
|
||||
| `-n, --nonce` | 自定义随机字符串 |
|
||||
| `--version` | 显示版本信息 |
|
||||
|
||||
### 常用命令示例
|
||||
|
||||
**基本用法**
|
||||
|
||||
```bash
|
||||
./target/release/apisign
|
||||
```
|
||||
|
||||
**自定义参数**
|
||||
|
||||
```bash
|
||||
./target/release/apisign \
|
||||
-u "https://api.example.com/user/info" \
|
||||
-p "userId=12345" -p "action=getInfo" \
|
||||
-k "YOUR_ACCESS_KEY" \
|
||||
-s "YOUR_SECRET_KEY" \
|
||||
-c "3"
|
||||
```
|
||||
|
||||
**指定签名算法**
|
||||
|
||||
```bash
|
||||
./target/release/apisign -a sha256
|
||||
```
|
||||
|
||||
**生成签名参数**
|
||||
|
||||
```bash
|
||||
./target/release/apisign -m sign_params -p "userId=12345" -p "action=getData"
|
||||
```
|
||||
|
||||
**验证签名**
|
||||
|
||||
```bash
|
||||
./target/release/apisign -m verify -p "userId=12345" -p "action=getData" -p "AccessKeyId=test-key" -p "channelId=test-channel" -p "timestamp=1621234567890" -p "nonce=abc123" -p "sign=calculated-signature-here"
|
||||
```
|
||||
|
||||
**帮助信息**
|
||||
|
||||
```bash
|
||||
./target/release/apisign --help
|
||||
```
|
||||
|
||||
### API接口测试实例
|
||||
|
||||
使用真实API接口进行测试:
|
||||
|
||||
```bash
|
||||
# 未签名的API调用测试 - 返回错误
|
||||
curl "https://api-v1.sound-force.com:8443/p/album/single/media-url?channelId=3&singleId=381980"
|
||||
# 返回: {"code":400,"data":null,"msg":"Missing AccessKeyId","success":false}
|
||||
|
||||
# 生成访问https://api-v1.sound-force.com:8443/p/album/single/media-url的签名URL
|
||||
./target/release/apisign \
|
||||
-a md5 \
|
||||
-u "https://api-v1.sound-force.com:8443/p/album/single/media-url" \
|
||||
-p "singleId=381980" \
|
||||
-k "YOUR_ACCESS_KEY" \
|
||||
-s "YOUR_SECRET_KEY" \
|
||||
-c "3"
|
||||
|
||||
# 使用curl测试API接口
|
||||
signed_url=$(./target/release/apisign \
|
||||
-a md5 \
|
||||
-u "https://api-v1.sound-force.com:8443/p/album/single/media-url" \
|
||||
-p "singleId=381980" \
|
||||
-k "YOUR_ACCESS_KEY" \
|
||||
-s "YOUR_SECRET_KEY" \
|
||||
-c "3" | grep -A 1 "签名后的URL:" | tail -n 1)
|
||||
curl -v "$signed_url"
|
||||
```
|
||||
|
||||
请注意:
|
||||
|
||||
- 替换`YOUR_ACCESS_KEY`为实际的访问密钥ID
|
||||
- 替换`YOUR_SECRET_KEY`为实际的密钥
|
||||
- 示例使用的渠道ID为`3`,请根据实际情况调整
|
||||
|
||||
使用有效的密钥和签名后,API接口将返回成功响应(状态码200)并提供媒体URL数据。
|
||||
|
||||
### Rust Reqwest客户端测试示例
|
||||
|
||||
```rust
|
||||
use std::process::Command;
|
||||
use reqwest;
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// 获取签名URL
|
||||
let output = Command::new("./target/release/apisign")
|
||||
.args(&[
|
||||
"-a", "md5",
|
||||
"-u", "https://api-v1.sound-force.com:8443/p/album/single/media-url",
|
||||
"-p", "singleId=381980",
|
||||
"-k", "YOUR_ACCESS_KEY",
|
||||
"-s", "YOUR_SECRET_KEY",
|
||||
"-c", "3"
|
||||
])
|
||||
.output()?;
|
||||
|
||||
let output_str = String::from_utf8(output.stdout)?;
|
||||
let lines: Vec<&str> = output_str.lines().collect();
|
||||
|
||||
// 提取URL
|
||||
let mut signed_url = "";
|
||||
for (i, line) in lines.iter().enumerate() {
|
||||
if line.contains("签名后的URL:") && i + 1 < lines.len() {
|
||||
signed_url = lines[i + 1].trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
println!("签名生成的URL: {}", signed_url);
|
||||
|
||||
if !signed_url.is_empty() {
|
||||
// 发送请求
|
||||
let client = reqwest::Client::new();
|
||||
let response = client.get(signed_url).send().await?;
|
||||
|
||||
println!("状态码: {}", response.status());
|
||||
let body = response.text().await?;
|
||||
println!("响应内容: {}", body);
|
||||
} else {
|
||||
println!("无法从输出中获取签名URL");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### 代码集成
|
||||
|
||||
```rust
|
||||
use apisign::{ApiSigner, SignOptions, SignatureAlgorithm};
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
// 创建签名选项
|
||||
let options = SignOptions::new()
|
||||
.with_algorithm(SignatureAlgorithm::Md5);
|
||||
|
||||
// 创建签名工具
|
||||
let signer = ApiSigner::new(options);
|
||||
|
||||
// 准备请求参数
|
||||
let mut params = HashMap::new();
|
||||
params.insert("singleId".to_string(), "381980".to_string());
|
||||
|
||||
// 执行签名
|
||||
let signed_params = signer.sign_request(
|
||||
¶ms,
|
||||
"YOUR_ACCESS_KEY",
|
||||
"YOUR_SECRET_KEY",
|
||||
"3"
|
||||
).unwrap();
|
||||
|
||||
// 或签名URL
|
||||
let signed_url = signer.sign_url(
|
||||
"https://api-v1.sound-force.com:8443/p/album/single/media-url",
|
||||
¶ms,
|
||||
"YOUR_ACCESS_KEY",
|
||||
"YOUR_SECRET_KEY",
|
||||
"3"
|
||||
).unwrap();
|
||||
|
||||
println!("{}", signed_url);
|
||||
}
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
该工具支持从`.env`文件加载以下配置:
|
||||
|
||||
- `ACCESS_KEY_ID`: 访问密钥ID
|
||||
- `SECRET_KEY`: 密钥
|
||||
- `CHANNEL_ID`: 渠道ID
|
||||
- `SIGN_ALGORITHM`: 签名算法
|
||||
- `API_BASE_URL`: API基础URL
|
||||
Reference in New Issue
Block a user