You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Golang中实现单腿OAuth 1签名API请求?

在Go中实现单腿OAuth 1.0 API调用(仅用Consumer Key/Secret)

单腿OAuth 1.0(无请求令牌/访问令牌,仅使用Consumer Key和Consumer Secret)的核心是按照OAuth 1.0规范生成正确的签名和Authorization请求头。以下是完整的Go实现代码,直接对应你在Postman中的操作逻辑:

完整实现代码

package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"time"
)

// 生成随机Nonce(16位字符串)
func generateNonce() string {
	rand.Seed(time.Now().UnixNano())
	chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	nonce := make([]byte, 16)
	for i := range nonce {
		nonce[i] = chars[rand.Intn(len(chars))]
	}
	return string(nonce)
}

// 构造OAuth 1.0 Authorization头
func createOAuth1Header(method, urlStr string, consumerKey, consumerSecret string) (string, error) {
	// 解析目标URL
	parsedURL, err := url.Parse(urlStr)
	if err != nil {
		return "", err
	}

	// 生成OAuth核心参数
	oauthParams := url.Values{
		"oauth_consumer_key":     {consumerKey},
		"oauth_nonce":            {generateNonce()},
		"oauth_timestamp":        {strconv.FormatInt(time.Now().Unix(), 10)},
		"oauth_signature_method": {"HMAC-SHA1"},
		"oauth_version":          {"1.0"},
	}

	// 1. 构造基础签名字符串:方法 + & + URL编码的基础URL + & + URL编码的参数串
	// 基础URL:协议+主机+路径(不含查询参数)
	baseURL := fmt.Sprintf("%s://%s%s", parsedURL.Scheme, parsedURL.Host, parsedURL.Path)
	encodedBaseURL := url.QueryEscape(baseURL)

	// 合并所有参数(包括URL查询参数)并按key排序
	allParams := make(url.Values)
	for k, v := range oauthParams {
		allParams[k] = v
	}
	for k, v := range parsedURL.Query() {
		allParams[k] = v
	}

	// 排序参数键
	sortedKeys := make([]string, 0, len(allParams))
	for k := range allParams {
		sortedKeys = append(sortedKeys, k)
	}
	sort.Strings(sortedKeys)

	// 构造参数字符串(key=编码后的value,按&拼接)
	var paramStr string
	for i, k := range sortedKeys {
		if i > 0 {
			paramStr += "&"
		}
		paramStr += fmt.Sprintf("%s=%s", url.QueryEscape(k), url.QueryEscape(allParams.Get(k)))
	}
	encodedParamStr := url.QueryEscape(paramStr)

	// 基础签名字符串
	signatureBaseStr := fmt.Sprintf("%s&%s&%s", method, encodedBaseURL, encodedParamStr)

	// 2. 生成HMAC-SHA1签名
	signatureKey := fmt.Sprintf("%s&", consumerSecret) // 单腿OAuth无token secret,所以后缀为&
	h := hmac.New(sha1.New, []byte(signatureKey))
	h.Write([]byte(signatureBaseStr))
	signatureBytes := h.Sum(nil)
	signatureBase64 := base64.StdEncoding.EncodeToString(signatureBytes)
	encodedSignature := url.QueryEscape(signatureBase64)

	// 3. 构造Authorization头
	oauthParams.Set("oauth_signature", encodedSignature)
	var authHeaderParts []string
	for k, v := range oauthParams {
		authHeaderParts = append(authHeaderParts, fmt.Sprintf(`%s="%s"`, k, url.QueryEscape(v[0])))
	}
	sort.Strings(authHeaderParts) // 按key排序,避免签名不一致
	authHeader := fmt.Sprintf("OAuth %s", joinStrings(authHeaderParts, ", "))

	return authHeader, nil
}

// 辅助函数:用分隔符拼接字符串切片
func joinStrings(slice []string, sep string) string {
	var result string
	for i, s := range slice {
		if i > 0 {
			result += sep
		}
		result += s
	}
	return result
}

// 发起API请求示例
func main() {
	// 替换为你的实际参数
	consumerKey := "your_authentication_key"
	consumerSecret := "your_authentication_secret"
	apiURL := "https://api.example.com/your-endpoint"
	method := "GET" // 或POST/PUT等

	// 生成Authorization头
	authHeader, err := createOAuth1Header(method, apiURL, consumerKey, consumerSecret)
	if err != nil {
		fmt.Printf("生成OAuth头失败: %v\n", err)
		return
	}

	// 创建HTTP请求
	req, err := http.NewRequest(method, apiURL, nil)
	if err != nil {
		fmt.Printf("创建请求失败: %v\n", err)
		return
	}

	// 添加Authorization头
	req.Header.Add("Authorization", authHeader)

	// 发起请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("发起请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	fmt.Printf("请求状态码: %d\n", resp.StatusCode)
	// 后续可处理响应内容
}

关键逻辑说明

  1. Nonce与Timestamp:Nonce是随机字符串(防止重放攻击),Timestamp是当前Unix时间戳,两者每次请求都要重新生成。
  2. 基础签名字符串:必须严格按照HTTP方法&URL编码的基础URL&URL编码的参数串格式构造,参数需按字典序排序,这是签名正确的核心。
  3. 签名生成:使用HMAC-SHA1算法,密钥为Consumer Secret&(单腿OAuth无Token Secret,所以后缀保留&),生成的签名需Base64编码后再URL编码。
  4. Authorization头:所有OAuth参数需格式化为key="value"的形式,value需URL编码,参数间用逗号分隔。

内容的提问来源于stack exchange,提问作者Angelo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:36:11