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

如何使用C#结合RestSharp调用Flickr API发布内容并生成oauth_signature

C# 结合 RestSharp 调用 Flickr API 动态生成 OAuth 签名实现方案

1. 基础规则说明

OAuth 1.0 HMAC-SHA1 签名生成需严格遵循以下规则:

  • oauth_timestamp:取当前 Unix 时间戳(秒级,从1970-01-01 00:00:00 UTC到现在的秒数)
  • oauth_nonce:每次请求生成唯一随机字符串,长度无强制要求,通常用随机字符或GUID截取
  • 签名生成步骤:
    • 收集所有OAuth参数(不含oauth_signature)和请求业务参数,按参数名ASCII码升序排序
    • 对每个参数的键和值分别做OAuth规范的URL编码,拼接为key=value格式,用&连接所有参数得到参数串
    • 拼接签名基础串:大写HTTP方法&编码后的请求基础地址&编码后的参数串
    • 构造签名密钥:编码后的Consumer Secret&编码后的Access Token Secret,无Access Token时保留末尾的&
    • 用HMAC-SHA1算法以签名密钥加密基础串,加密结果做Base64编码后再做URL编码,即为oauth_signature的值

2. 工具方法实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

public static class OAuth1Helper
{
    // 生成符合OAuth规范的URL编码
    private static string UrlEncode(string value)
    {
        if (string.IsNullOrEmpty(value)) return string.Empty;
        var unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        var result = new StringBuilder();
        foreach (char symbol in Encoding.UTF8.GetBytes(value))
        {
            if (unreservedChars.IndexOf(symbol) != -1)
            {
                result.Append(symbol);
            }
            else
            {
                result.Append('%' + string.Format("{0:X2}", (int)symbol));
            }
        }
        return result.ToString();
    }

    // 生成oauth_timestamp
    public static string GenerateTimeStamp()
    {
        return Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds).ToString();
    }

    // 生成oauth_nonce
    public static string GenerateNonce(int length = 11)
    {
        var random = new Random();
        var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
    }

    // 生成HMAC-SHA1签名
    public static string GenerateSignature(string httpMethod, string baseUrl, SortedDictionary<string, string> parameters, string consumerSecret, string tokenSecret = "")
    {
        // 拼接参数串
        var paramStr = string.Join("&", parameters.Select(p => $"{UrlEncode(p.Key)}={UrlEncode(p.Value)}"));
        // 拼接签名基础串
        var signatureBase = $"{httpMethod.ToUpper()}&{UrlEncode(baseUrl)}&{UrlEncode(paramStr)}";
        // 构造密钥
        var secretKey = $"{UrlEncode(consumerSecret)}&{UrlEncode(tokenSecret)}";
        // HMAC-SHA1加密
        using (var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(secretKey)))
        {
            var hashBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureBase));
            return UrlEncode(Convert.ToBase64String(hashBytes));
        }
    }
}

3. 接口修改后完整代码

public class TestController : Controller
{
    // 替换为自己的Flickr应用凭证
    private const string ConsumerKey = "你的consumer_key";
    private const string ConsumerSecret = "你的consumer_secret";
    private const string AccessToken = "你的token_key";
    private const string AccessTokenSecret = "你的token_secret";
    private const string CallbackUrl = "你的callback_url";
    private const string VerifierKey = "你的verifier_key";

    [HttpGet("GetFlickr")]
    public ActionResult GetFlickr()
    {
        var client = new RestClient("https://api.flickr.com/services/upload/");
        client.Timeout = -1;
        var request = new RestRequest(Method.POST);

        // 动态生成时间戳和随机数
        var timestamp = OAuth1Helper.GenerateTimeStamp();
        var nonce = OAuth1Helper.GenerateNonce();

        // 收集所有OAuth参数(按升序排序满足签名要求)
        var oauthParams = new SortedDictionary<string, string>
        {
            {"oauth_consumer_key", ConsumerKey},
            {"oauth_token", AccessToken},
            {"oauth_signature_method", "HMAC-SHA1"},
            {"oauth_timestamp", timestamp},
            {"oauth_nonce", nonce},
            {"oauth_version", "1.0"},
            {"oauth_callback", CallbackUrl},
            {"oauth_verifier", VerifierKey}
        };

        // 生成签名
        var signature = OAuth1Helper.GenerateSignature("POST", "https://api.flickr.com/services/upload/", oauthParams, ConsumerSecret, AccessTokenSecret);
        oauthParams.Add("oauth_signature", signature);

        // 构造Authorization头
        var authHeader = "OAuth " + string.Join(",", oauthParams.Select(p => $"{p.Key}=\"{p.Value}\""));
        request.AddHeader("Authorization", authHeader);

        request.AddFile("photo", "/C:/Users/oguzm/OneDrive/Masaüstü/Ekran Alıntısı.PNG");
        IRestResponse response = client.Execute(request);
        return Ok(response);
    }
}

注意:如果请求包含其他业务参数,需要把这些参数也加入到生成签名用的SortedDictionary中,否则会出现签名校验失败的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 01:12:01