简体   繁体   中英

Publish article for Apple news API using C# - (401) Unauthorized

I am working on posting article using Apple news API.

I created new account and also created new channel.

Below is the code snippet which I am using.

        string channel_id = "{Channel_Id}";
        string api_key_id = "{Key_Id}";
        string api_key_secret = "{Secret}";
        var path = "https://news-api.apple.com/channels/" + channel_id + "/articles";

        var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
        httpWebRequest.ContentType = "multipart/form-data";
        httpWebRequest.Method = "POST";
        httpWebRequest.Accept = "application/json";
        httpWebRequest.Host = "news-api.apple.com";
        httpWebRequest.UseDefaultCredentials = true;
        httpWebRequest.PreAuthenticate = true;

        httpWebRequest.ProtocolVersion = HttpVersion.Version11;
        httpWebRequest.KeepAlive = true;
        string appleDate = String.Format("{0}Z", DateTime.UtcNow.ToString("s"));
        string credentials = String.Format("{0}:{1}", "Content-Disposition", "form-data; ");
        credentials += String.Format("{0}:{1}", "filename", "article.json; ");
        credentials += String.Format("{0}:{1}", "name", "article.json; ");

        credentials += String.Format("{0}","HHMAC; ");
        credentials += String.Format("{0}={1}", "key", api_key_id + "; ");

        string decodedSecret = base64Decode(api_key_secret);
        string canonical_request = path + "POST" + appleDate ;
        string hash = Class1.HmacSha256Digest(canonical_request, decodedSecret);
        string Encodedhash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(hash));

        credentials += String.Format("{0}={1}", "signature", Encodedhash + "; ");
        credentials += String.Format("{0}={1}", "date", appleDate + "; ");


        httpWebRequest.Headers.Add("Authorization", credentials);

        using (StreamReader r = new StreamReader(Directory.GetCurrentDirectory() + ("/article.json")))
        {
            string json = r.ReadToEnd();
            dynamic jsonObj = JsonConvert.DeserializeObject(json);

            ASCIIEncoding encoding = new ASCIIEncoding();
            Byte[] bytes = encoding.GetBytes(json);
            Stream newStream = httpWebRequest.GetRequestStream();
            newStream.Write(bytes, 0, bytes.Length);
            newStream.Close();
        }
        var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var result = streamReader.ReadToEnd();
        }

Here is base64Decode function

public static string base64Decode(string data)
        {
            var base64EncodedBytes = System.Convert.FromBase64String(data);
            return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
        }

Here is class to convert Sha256Digest

public static class Class1
    {
        public static string HmacSha256Digest(this string message, string secret)
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] keyBytes = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);

            byte[] bytes = cryptographer.ComputeHash(messageBytes);

            return BitConverter.ToString(bytes).Replace("-", "").ToLower();
        }
    }

Whenever I am trying to post the API I am getting below error message:

"'The remote server returned an error: (401) Unauthorized".

When I am trying to post the API request using Postman then I am getting below error message:

{
    "errors": [
        {
            "code": "WRONG_SIGNATURE"
        }
    ]
}

Is there anything incorrect to generate Signature ?

I researched few articles but unable to find any solution.

Please guide me to find out the solution on this.

I don't have time to go through the entirety of your code and suggest you start with a simpler Channel Data request before attempting to POST json, but a potential couple of bits I noticed:

  1. You use ASCII encoding where you should be using UTF8 throughout.
  2. You strip hyphens from the Base64 but Apple only strips returns and whitespace
  3. The cannonical request should be written: "POST[url][date][contentType]" where url = "https://news-api.apple.com/channels/[channelID]/articles" , date is in the format "yyyy-MM-dd'T'HH:mm:ss'Z'" and content-type = "multipart/form-data; boundary=[boundary]" where boundary is any string used to divide the content.

See also my tips on using Python , most importantly ensure you are using the path to a folder containing article.json (not the path to a file). And finally here is my own translation of the Python into Swift.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM