Invalid signature for signing requests to the Flickr API (simulation in console)

前端 未结 2 1051
醉话见心
醉话见心 2020-12-15 13:57

I\'m trying to authenticate to the Flickr API for a demo application I want to make for myself. Then i will extend this app with new features that i\'ll learn of the Flick A

相关标签:
2条回答
  • 2020-12-15 14:16

    Are you writing this from scratch? If so, you shouldn't. Use http://flickrnet.codeplex.com/ instead. This library has already done the heavy lifting for you.

    0 讨论(0)
  • 2020-12-15 14:31

    Ok, I finally found the answer myself. Here are a few things you have to keep in mind when signing requests for oauth.

    1. signature must be encrypted with HMAC-SHA1 using the basestring(see nr.2) as text to be encrypted and the clientsecret and the token_secret (if you have one) (see nr. 3)
    2. basestring = [HttpMethod]&[FlickrAPIEndpoint]&[Parameters]
    3. Key for request oauth_token = [ApiSecret]& (or key = [ApiSecret]&[Oauth_token_secret] for request access_token)

    IMPORTANT: FlickrAPIEndPoint and Parameters must be UrlEncoded (in two parts!) I have used a separate class for the encoding because the HttpUtility.UrlEncode method uses lowercase encoding while the uppercase encoding should be used.

    IMPORTANT: Parameters must be in alphabetical order!

    Here's the code for a console application that will create a signed request for a request token and a request token secret.

    class Program
    {
        private static string Secret = "9dcc18a121e9a02e";
        private static string ConsumerKey = "3aafc63ec6b05f3f9a9ff3a1c35ce541";
        private static string request_token = "";
    
        static void Main(string[] args)
        {
    
            string requestString = "http://www.flickr.com/services/oauth/request_token";
    
            //generate a random nonce and a timestamp
            Random rand = new Random();
            string nonce = rand.Next(999999).ToString();
            string timestamp = GetTimestamp();
    
            //create the parameter string in alphabetical order
            string parameters = "oauth_callback=" + UrlHelper.Encode("http://www.example.com");
            parameters += "&oauth_consumer_key=" + ConsumerKey;
            parameters += "&oauth_nonce=" + nonce;
            parameters += "&oauth_signature_method=HMAC-SHA1";
            parameters += "&oauth_timestamp=" + timestamp;
            parameters += "&oauth_version=1.0";
    
            //generate a signature base on the current requeststring and parameters
            string signature = generateSignature("GET", requestString, parameters);
    
            //add the parameters and signature to the requeststring
            string url = requestString + "?" + parameters + "&oauth_signature=" + signature;
    
            //test the request
            WebClient web = new WebClient();
            string result = web.DownloadString(url);
    
            Console.WriteLine("Flickr Response: ");
            Console.WriteLine(result); //contains the oauth_token and the oauth_token_secret
            Console.ReadKey(true);
    
        }
    
        private static string generateSignature(string httpMethod, string ApiEndpoint, string parameters)
        {
            //url encode the API endpoint and the parameters 
    
            //IMPORTANT NOTE:
            //encoded text should contain uppercase characters: '=' => %3D !!! (not %3d )
            //the HtmlUtility.UrlEncode creates lowercase encoded tags!
            //Here I use a urlencode class by Ian Hopkins
            string encodedUrl = UrlHelper.Encode(ApiEndpoint);
            string encodedParameters = UrlHelper.Encode(parameters);
    
            //generate the basestring
            string basestring = httpMethod + "&" + encodedUrl + "&";
            parameters = UrlHelper.Encode(parameters);
            basestring = basestring + parameters;
    
            //hmac-sha1 encryption:
    
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    
            //create key (request_token can be an empty string)
            string key = Secret + "&" + request_token;
            byte[] keyByte = encoding.GetBytes(key);
    
            //create message to encrypt
            byte[] messageBytes = encoding.GetBytes(basestring);
    
            //encrypt message using hmac-sha1 with the provided key
            HMACSHA1 hmacsha1 = new HMACSHA1(keyByte);
            byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
    
            //signature is the base64 format for the genarated hmac-sha1 hash
            string signature = System.Convert.ToBase64String(hashmessage);
    
            //encode the signature to make it url safe and return the encoded url
            return UrlHelper.Encode(signature);
    
        }
    
        //generator of unix epoch time
        public static String GetTimestamp()
        {
            int epoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            return epoch.ToString();
        } 
    
    }
    

    UrlHelper class by Ian Hopkins used for the url encoding

    /// <summary> 
        /// URL encoding class.  Note: use at your own risk. 
        /// Written by: Ian Hopkins (http://www.lucidhelix.com) 
        /// Date: 2008-Dec-23 
        /// (Ported to C# by t3rse (http://www.t3rse.com)) 
        /// </summary> 
        public class UrlHelper
        {
            public static string Encode(string str)
            {
                var charClass = String.Format("0-9a-zA-Z{0}", Regex.Escape("-_.!~*'()"));
                return Regex.Replace(str,
                    String.Format("[^{0}]", charClass),
                    new MatchEvaluator(EncodeEvaluator));
            }
        public static string EncodeEvaluator(Match match)
        {
            return (match.Value == " ") ? "+" : String.Format("%{0:X2}", Convert.ToInt32(match.Value[0]));
        }
    
        public static string DecodeEvaluator(Match match)
        {
            return Convert.ToChar(int.Parse(match.Value.Substring(1), System.Globalization.NumberStyles.HexNumber)).ToString();
        }
    
        public static string Decode(string str)
        {
            return Regex.Replace(str.Replace('+', ' '), "%[0-9a-zA-Z][0-9a-zA-Z]", new MatchEvaluator(DecodeEvaluator));
        }
    } 
    
    0 讨论(0)
提交回复
热议问题