# API签名工具 - Go实现 ## 项目结构 根据实际项目文件结构: ```plaintext go/ ├── main.go # 主程序入口 ├── apisign/ # 签名库核心代码目录 │ └── signer.go # 签名工具实现 ├── go.mod # Go模块定义 └── go.sum # 依赖版本锁定 ``` ## 使用方法 ### 构建项目 ```bash go build -o apisign ``` ### 运行命令行工具 ```bash ./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` | 自定义时间戳 | ### 常用命令示例 **基本用法** ```bash ./apisign ``` **自定义参数** ```bash ./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 ./apisign -a sha256 ``` **生成签名参数** ```bash ./apisign -m params -p "userId=12345" -p "action=getData" ``` **验证签名** ```bash ./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 ./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 ./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客户端测试示例 ```go 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) } ``` ### 代码集成 ```go 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`: 访问密钥ID - `SECRET_KEY`: 密钥 - `CHANNEL_ID`: 渠道ID - `SIGN_ALGORITHM`: 签名算法 - `API_BASE_URL`: API基础URL