Golang单脚OAuth1的实现与问题讨论

Golang单脚OAuth1的实现与问题讨论 我正在尝试生成一个令牌,以便能够进行单腿 OAuth 1 API 调用,但我很难理解如何在 Golang 中实现。

我也找不到相关的包。希望有人能帮助我。

我尝试在 Postman 中使其正常工作,这运行得很好。

    req.Header.Add("Authorization", "OAuth oauth_consumer_key=\"xxxx\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1712582585\",oauth_nonce=\"xxxx\",oauth_version=\"1.0\",oauth_signature=\"xxxx\"")

但现在我需要将其转换为 Golang。我拥有的数据是一个 authentication_key 和一个 authentication_secret

这就是我进行 API 调用所需的全部内容。

希望有人能帮助我了解如何创建带有正确签名的请求。

我尝试寻找相关的包,但据我所见,没有一个支持单腿 OAuth 1 调用。


更多关于Golang单脚OAuth1的实现与问题讨论的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

您将需要以下标准的 Go 语言库:

  • net/http 用于发起 HTTP 请求。
  • crypto/hmaccrypto/sha1 用于生成 HMAC-SHA1 签名。
  • url 用于 URL 编码。
  • time 用于生成时间戳。

更多关于Golang单脚OAuth1的实现与问题讨论的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


对于单腿OAuth 1的实现,可以使用oauth1包配合自定义签名方法。以下是一个完整的示例:

package main

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

// 生成OAuth 1.0a签名
func generateSignature(method, url, consumerSecret string, params map[string]string) string {
    // 1. 收集参数
    paramString := ""
    for k, v := range params {
        if paramString != "" {
            paramString += "&"
        }
        paramString += fmt.Sprintf("%s=%s", k, v)
    }
    
    // 2. 构建签名基础字符串
    signatureBase := strings.ToUpper(method) + "&" +
        percentEncode(url) + "&" +
        percentEncode(paramString)
    
    // 3. 生成签名密钥(单腿OAuth只需要consumer_secret)
    signingKey := percentEncode(consumerSecret) + "&"
    
    // 4. 计算HMAC-SHA1
    mac := hmac.New(sha1.New, []byte(signingKey))
    mac.Write([]byte(signatureBase))
    signature := mac.Sum(nil)
    
    // 5. Base64编码
    return base64.StdEncoding.EncodeToString(signature)
}

// URL编码(符合OAuth规范)
func percentEncode(s string) string {
    return strings.ReplaceAll(
        strings.ReplaceAll(
            strings.ReplaceAll(s, "%", "%25"),
            "+", "%2B",
        ),
        " ", "%20",
    )
}

// 生成随机nonce
func generateNonce() string {
    return fmt.Sprintf("%d", rand.Int63())
}

// 创建OAuth 1.0a头部
func createOAuthHeader(consumerKey, consumerSecret, method, url string) string {
    timestamp := strconv.FormatInt(time.Now().Unix(), 10)
    nonce := generateNonce()
    
    params := map[string]string{
        "oauth_consumer_key":     consumerKey,
        "oauth_nonce":            nonce,
        "oauth_signature_method": "HMAC-SHA1",
        "oauth_timestamp":        timestamp,
        "oauth_version":          "1.0",
    }
    
    signature := generateSignature(method, url, consumerSecret, params)
    
    return fmt.Sprintf(
        `OAuth oauth_consumer_key="%s",oauth_nonce="%s",oauth_signature="%s",oauth_signature_method="HMAC-SHA1",oauth_timestamp="%s",oauth_version="1.0"`,
        consumerKey,
        nonce,
        percentEncode(signature),
        timestamp,
    )
}

func main() {
    consumerKey := "your_authentication_key"
    consumerSecret := "your_authentication_secret"
    apiURL := "https://api.example.com/endpoint"
    
    // 创建请求
    req, err := http.NewRequest("GET", apiURL, nil)
    if err != nil {
        panic(err)
    }
    
    // 添加OAuth头部
    oauthHeader := createOAuthHeader(consumerKey, consumerSecret, "GET", apiURL)
    req.Header.Add("Authorization", oauthHeader)
    
    // 发送请求
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    fmt.Println("Response Status:", resp.Status)
}

如果需要使用现有的包,可以使用github.com/dghubble/oauth1并自定义Token:

package main

import (
    "github.com/dghubble/oauth1"
    "net/http"
    "fmt"
)

func main() {
    config := oauth1.Config{
        ConsumerKey:    "your_authentication_key",
        ConsumerSecret: "your_authentication_secret",
        // 单腿OAuth不需要回调URL
        CallbackURL: "",
        // 单腿OAuth不需要Endpoint
        Endpoint: oauth1.Endpoint{},
    }
    
    // 创建单腿OAuth Token(无Token和Secret)
    token := oauth1.NewToken("", "")
    
    // 创建HTTP客户端
    httpClient := config.Client(oauth1.NoContext, token)
    
    // 发送请求
    resp, err := httpClient.Get("https://api.example.com/endpoint")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    fmt.Println("Response Status:", resp.Status)
}

对于更复杂的场景(如包含查询参数),需要调整签名生成逻辑:

func generateSignatureWithQueryParams(method, baseURL, queryString, consumerSecret string, oauthParams map[string]string) string {
    // 合并所有参数
    allParams := make(map[string]string)
    
    // 添加OAuth参数
    for k, v := range oauthParams {
        allParams[k] = v
    }
    
    // 解析并添加查询参数
    if queryString != "" {
        pairs := strings.Split(queryString, "&")
        for _, pair := range pairs {
            kv := strings.Split(pair, "=")
            if len(kv) == 2 {
                allParams[kv[0]] = kv[1]
            }
        }
    }
    
    // 生成参数字符串(按键排序)
    keys := make([]string, 0, len(allParams))
    for k := range allParams {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    
    paramString := ""
    for _, k := range keys {
        if paramString != "" {
            paramString += "&"
        }
        paramString += fmt.Sprintf("%s=%s", k, percentEncode(allParams[k]))
    }
    
    // 继续签名生成...
    // ...(使用之前的generateSignature函数逻辑)
}

这些示例展示了如何在Golang中实现单腿OAuth 1.0a认证。第一个示例提供了完整的底层实现,第二个示例展示了如何使用现有包进行简化。

回到顶部