我们正在使用UpgradeableApp API资源迁移Google Apps Marketplace列表,但在调用时 PUT https://www.googleapis.com/appsmarket/v2/upgradableApp/listingID/cwsID/domain 签名请求收到错误:
81 {"error":{"errors":[{"domain":"global","reason":"backendError","message":"Backend Error"}],"code":500,"message":"Backend Error"}} 0
我做错了什么......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OAuth.Net.Common;
using OAuth.Net.Components;
using System.IO;
using System.Net;
using System.Security.Cryptography;
namespace Google_UpgradeableApi_Console
{
class Program
{
private static readonly ISigningProvider SigningProvider = new HmacSha1SigningProvider();
static void Main(string[] args)
{
// Setup the variables necessary to create the OAuth 1.0 signature and make the request
string httpMethod = "PUT";
string listingID = "xxxx+23453809800066606066";
string cwsID = "bbmagicjcjeblpadhhnnjahfbbbbhjk";
string domain = "xyz.com";
Uri url = new Uri(String.Format("{0}/{1}/{2}/{3}", "https://www.googleapis.com/appsmarket/v2/upgradableApp", listingID, cwsID, domain));
string consumerKey = "xyz.apps.googleusercontent.com";
string secret = "gt2sj34656U687f8qj677+GK";
string body = "";
MemoryStream requestBody = null;
string signatureMethod = SigningProvider.SignatureMethod;
HttpWebResponse response = null;
// Set the Nonce and Timestamp parameters
string nonce = getNonce();
string timestamp = getTimestamp();
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
requestBody = new MemoryStream(Encoding.UTF8.GetBytes(body));
}
// Create the OAuth parameter name/value pair dictionary
Dictionary<string, string> oauthParams = new Dictionary<string, string>
{
{ "oauth_consumer_key", consumerKey },
{ "oauth_signature_method", signatureMethod },
{ "oauth_timestamp", timestamp },
{ "oauth_nonce", nonce },
};
// Get the OAuth 1.0 Signature
string signature = generateSignature(httpMethod, url, oauthParams, requestBody, secret);
Console.WriteLine("OAuth 1.0 Signature = " + signature + "\r\n\r\n");
// Add the oauth_signature parameter to the set of OAuth Parameters
IEnumerable<KeyValuePair<string, string>> allParams = oauthParams.Union(new[]
{
new KeyValuePair<string, string>("oauth_signature", signature)
});
// Defines a query that produces a set of: keyname="URL-encoded(value)"
IEnumerable<string> encodedParams = from param in allParams
select param.Key + "=\"" + Uri.EscapeDataString(param.Value) + "\"";
// Join all encoded parameters with a comma delimiter and convert to a string
string stringParams = String.Join(",", encodedParams);
// Build the X-Authorization request header
string xauth = String.Format("X-Authorization: OAuth realm=\"{0}\",{1}", url, stringParams);
Console.WriteLine("X-Authorization request header: \r\n" + xauth + "\r\n\r\n");
try
{
// Setup the Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = httpMethod;
request.Headers.Add(xauth);
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
byte[] dataArray = Encoding.UTF8.GetBytes(body);
request.ContentLength = dataArray.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(dataArray, 0, dataArray.Length);
requestStream.Close();
}
// Send Request & Get Response
response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// Get the response stream and write to console
string json = reader.ReadToEnd();
Console.WriteLine("Successful Response: \r\n" + json);
}
}
catch (WebException e)
{
// This exception will be raised if the server didn't return 200 - OK
// Retrieve more information about the error
if (e.Response != null)
{
using (HttpWebResponse err = (HttpWebResponse)e.Response)
{
Console.WriteLine("The server returned '{0}' with the status code '{1} ({2:d})'.",
err.StatusDescription, err.StatusCode, err.StatusCode);
}
}
}
finally
{
if (response != null) { response.Close(); }
}
Console.ReadLine();
}
#region Helper Functions
/// <summary>
/// Generates a random nonce.
/// </summary>
/// <returns>A unique identifier for the request.</returns>
private static string getNonce()
{
string rtn = Path.GetRandomFileName() + Path.GetRandomFileName() + Path.GetRandomFileName();
rtn = rtn.Replace(".", "");
if (rtn.Length > 32)
return rtn.Substring(0, 32);
else
return rtn;
}
/// <summary>
/// Generates an integer representing the number of seconds since the unix epoch using the
/// UTC date/time of the request.
/// </summary>
/// <returns>A timestamp for the request.</returns>
private static string getTimestamp()
{
return ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
}
/// <summary>
/// Generates an OAuth 1.0 signature.
/// </summary>
/// <param name="httpMethod">The HTTP method of the request.</param>
/// <param name="url">The URI of the request.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <param name="secret">Alphanumeric string used to validate the identity of the education partner (Private Key).</param>
/// <returns>A string containing the BASE64-encoded signature digest.</returns>
private static string generateSignature(
string httpMethod,
Uri url,
IDictionary<string, string> oauthParams,
Stream requestBody,
string secret
)
{
// Ensure the HTTP Method is upper-cased
httpMethod = httpMethod.ToUpper();
// Construct the URL-encoded OAuth parameter portion of the signature base string
string encodedParams = normalizeParams(httpMethod, url, oauthParams, requestBody);
// URL-encode the relative URL
string encodedUri = Uri.EscapeDataString(url.AbsolutePath);
// Build the signature base string to be signed with the Consumer Secret
string baseString = String.Format("{0}&{1}&{2}", httpMethod, encodedUri, encodedParams);
//return generateCmac(secret, baseString);
return generateHMAC(secret, baseString);
}
/// <summary>
/// Normalizes all oauth signable parameters and url query parameters according to OAuth 1.0.
/// </summary>
/// <param name="httpMethod">The upper-cased HTTP method.</param>
/// <param name="url">The request URL.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <returns>A string containing normalized and encoded OAuth parameters.</returns>
private static string normalizeParams(
string httpMethod,
Uri url,
IEnumerable<KeyValuePair<string, string>> oauthParams,
Stream requestBody
)
{
IEnumerable<KeyValuePair<string, string>> kvpParams = oauthParams;
// Place any Query String parameters into a key value pair using equals ("=") to mark
// the key/value relationship and join each paramter with an ampersand ("&")
if (!String.IsNullOrWhiteSpace(url.Query))
{
IEnumerable<KeyValuePair<string, string>> queryParams =
from p in url.Query.Substring(1).Split('&').AsEnumerable()
let key = Uri.EscapeDataString(p.Substring(0, p.IndexOf("=")))
let value = Uri.EscapeDataString(p.Substring(p.IndexOf("=") + 1))
select new KeyValuePair<string, string>(key, value);
kvpParams = kvpParams.Union(queryParams);
}
// Include the body parameter if dealing with a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
MemoryStream ms = new MemoryStream();
requestBody.CopyTo(ms);
byte[] bodyBytes = ms.ToArray();
string body = Convert.ToBase64String(bodyBytes, Base64FormattingOptions.None);
body = Uri.EscapeDataString(body);
kvpParams = kvpParams.Union(new[]
{
new KeyValuePair<string, string>("body", Uri.EscapeDataString(body))
});
}
// Sort the parameters in lexicographical order, 1st by Key then by Value; separate with ("=")
IEnumerable<string> sortedParams =
from p in kvpParams
orderby p.Key ascending, p.Value ascending
select p.Key + "=" + p.Value;
// Add the ampersand delimiter and then URL-encode the equals ("%3D") and ampersand ("%26")
string stringParams = String.Join("&", sortedParams);
string encodedParams = Uri.EscapeDataString(stringParams);
return encodedParams;
}
private static string generateHMAC(string _key, string _msg)
{
string message;
string key;
key = _key;
message = _msg;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA1 hmacsha1 = new HMACSHA1(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
return ByteToString(hashmessage);
}
public static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
#endregion // Helper Functions
}
}
答案 0 :(得分:1)
这背后有很多原因,但首先请检查网址是否必须使用OAuth1(非OAuth2)进行签名,并且必须具有其他参数的有效值。错误报告可能会因为很多原因而抛出相同的错误,但请确保您的设置正确并确保您的应用程序在新的Chrome应用程序市场上发布。请务必在此处提交Google Apps Marketplace清单审核申请表:
https://docs.google.com/forms/d/14QOb8PbSLKDgwIp8Zv-luoAAVurPXUqtzL0Hgikp3rk/viewform
毕竟完成并获得谷歌批准(您将收到一封电子邮件)您的应用程序然后使用oAuth 1.0签名请求调用UpgradeableApp API,以下是一个示例,您可以看到如何执行此操作。
http://www.codeproject.com/Tips/359144/Legged-OAuth-Authentication-in-NET-Csharp
希望有所帮助