API签名工具 - Go实现
项目结构
根据实际项目文件结构:
go/
├── main.go # 主程序入口
├── apisign/ # 签名库核心代码目录
│ └── signer.go # 签名工具实现
├── go.mod # Go模块定义
└── go.sum # 依赖版本锁定
使用方法
构建项目
go build -o apisign
运行命令行工具
./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 |
操作模式: url, params, verify |
-n, --nonce |
自定义随机字符串 |
-t, --timestamp |
自定义时间戳 |
常用命令示例
基本用法
./apisign
自定义参数
./apisign \
-u "https://api.example.com/user/info" \
-p "userId=12345" -p "action=getInfo" \
-k "YOUR_ACCESS_KEY" \
-s "YOUR_SECRET_KEY" \
-c "3"
指定签名算法
./apisign -a sha256
生成签名参数
./apisign -m params -p "userId=12345" -p "action=getData"
验证签名
./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"
帮助信息
./apisign --help
API接口测试实例
使用真实API接口进行测试:
# 未签名的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
./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=$(./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数据。
Go HTTP客户端测试示例
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os/exec"
"strings"
)
func main() {
// 获取签名URL
cmd := exec.Command("./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")
output, err := cmd.CombinedOutput()
if err != nil {
panic(err)
}
// 从输出中提取URL
lines := strings.Split(string(output), "\n")
var url string
for i, line := range lines {
if strings.Contains(line, "签名后的URL:") && i+1 < len(lines) {
url = strings.TrimSpace(lines[i+1])
break
}
}
if url == "" {
panic("无法从输出中获取签名URL")
}
// 发送请求
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("状态码: %d\n", resp.StatusCode)
fmt.Printf("响应内容: %s\n", body)
}
代码集成
package main
import (
"fmt"
"github.com/soundforce/apisign"
)
func main() {
// 创建签名选项
options := apisign.NewOptions().
WithAlgorithm(apisign.MD5)
// 创建签名工具
signer := apisign.NewSigner(options)
// 准备请求参数
params := map[string]string{
"singleId": "381980",
}
// 执行签名
signedParams, err := signer.SignRequest(
params,
"YOUR_ACCESS_KEY",
"YOUR_SECRET_KEY",
"3",
)
if err != nil {
panic(err)
}
// 或签名URL
signedURL, err := signer.SignURL(
"https://api-v1.sound-force.com:8443/p/album/single/media-url",
params,
"YOUR_ACCESS_KEY",
"YOUR_SECRET_KEY",
"3",
)
if err != nil {
panic(err)
}
fmt.Println(signedURL)
}
环境变量
该工具支持从.env文件加载以下配置:
ACCESS_KEY_ID: 访问密钥IDSECRET_KEY: 密钥CHANNEL_ID: 渠道IDSIGN_ALGORITHM: 签名算法API_BASE_URL: API基础URL