如何使用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
相关产品推荐
相关产品推荐

