以前紹介した、NetSuiteのREST APIをPostmanから投げたのと同じように、C#からリクエストを投げたいと考えましたが、実装できるまで苦労したので記録用に。
前提
-
HttpClient
を使ってリクエストを投げる - .NET Framework 4.7.2を使用
- 認証に使うtokenなどはきちんと発行されている
- TBA認証
0. 必要な値の準備
今回はサンプルとして、以下の値を使います。
値は以下のサイトから。
名前 | 値 |
---|---|
URL | https://123456.suitetalk.api.netsuite.com/services/rest/record/v1/employee/40 |
HttpMethod | Get |
TokenKey | 2b0ce516420110bcbd36b69e99196d1b7f6de3c6234c5afb799b73d87569f5cc |
TokenSecret | c29a677df7d5439a458c063654187e3d678d73aca8e3c9d8bea1478a3eb0d295 |
ConsumerKey | ef40afdd8abaac111b13825dd5e5e2ddddb44f86d5a0dd6dcf38c20aae6b67e4 |
ConsumerSecret | d26ad321a4b2f23b0741c8d38392ce01c3e23e109df6c96eac6d099e9ab9e8b5 |
SignatureMethod | HMAC-SHA256 |
Nonce (固定値ではない) | fjaLirsIcCGVZWzBX0pg |
Timestamp (固定値ではない) | 1508242306 |
Version | 1.0 |
Realm (AccountId) | 123456 |
1. Signatureを作る
以下の資料を参考に、Signatureを作る処理をメソッドを実装していきます。
1-1. メソッドを作る
引数でHttpMethod
, url
, nonce
, timestamp
を受け取ります。
必要に応じて引数は追加してください。
public static string ComputeSignature(
HttpMethod httpMethod, string url, string tokenKey, string tokenSecret,
string consumerKey, string consumerSecret, string signatureMethod,
string nonce, string timestamp, string version
)
{
return "";
}
1-2. パラメータ無しのURLを取得
後で使うので、パラメータは取っておきます。
スキーマ (http、https) とホスト名は小文字である必要がありますが、今回は渡すときに小文字にするので処理は書いていません。
var baseUrl = url;
var getParams = "";
if (url.Contains("?"))
{
var index = url.IndexOf("?");
baseUrl = url.Substring(0, index);
getParams = url.Substring(index + 1);
}
1-3. パラメータを用意
まずは必須の値をリストに入れます。
var paramList = new List<string>()
{
"oauth_token=" + tokenKey,
"oauth_consumer_key=" + consumerKey,
"oauth_signature_method=" + signatureMethod,
"oauth_nonce=" + nonce,
"oauth_timestamp=" + timestamp,
"oauth_version=" + version,
};
次に、URLのパラメータをparamList
に追加していきます。
if (!string.IsNullOrEmpty(getParams))
{
foreach (var param in getParams.Split('&'))
{
var parsed = param.Split('=');
if (!string.IsNullOrEmpty(parsed[0]))
{
var name = Uri.UnescapeDataString(parsed[0]);
var value = parsed.Length >= 2 ? Uri.UnescapeDataString(parsed[1]) : "";
if (paramList.Any(x => x.StartsWith(value + "=")))
{
var removeParam = paramList.Where(x => x.StartsWith(value + "=")).FirstOrDefault();
paramList.Remove(removeParam);
}
paramList.Add(name + "=" + value);
}
}
}
パラメータを昇順に並び替え、"&"
でjoin
していきます。
paramList.Sort();
var baseParams = string.Join("&", paramList);
1-4. Base Stringを作る
HttpMethod
は大文字に、URLとParamはパーセントエンコーディングします。
var baseString = httpMethod.ToString().ToUpper()
+ "&" + Uri.UnescapeDataString(baseUrl)
+ "&" + Uri.UnescapeDataString(baseParams);
baseStringには、以下の値が入っているはずです。
GET&https%3A%2F%2F123456.suitetalk.api.netsuite.com%2Fservices%2Frest%2Frecord%2Fv1%2Femployee%2F40&oauth_consumer_key%3Def40afdd8abaac111b13825dd5e5e2ddddb44f86d5a0dd6dcf38c20aae6b67e4%26oauth_nonce%3DfjaLirsIcCGVZWzBX0pg%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1508242306%26oauth_token%3D2b0ce516420110bcbd36b69e99196d1b7f6de3c6234c5afb799b73d87569f5cc%26oauth_version%3D1.0
1-5. Signatureを作る
HMACで署名を作るためのキーを作成します。
var key = Uri.UnescapeDataString(consumerSecret) + "&" + Uri.UnescapeDataString(tokenSecret);
続いて、HMAC-SHA256で署名を作成していきます。
var signature = "";
var encording = new System.Text.ASCIIEncording();
using (var hmacsha256 = new HMACSHA256(encording.GetBytes(key)))
{
byte[] hashBaseString = hmacsha256.ComputeHash(encording.GetBytes(baseString));
signature = Convert.ToBase64String(hashBaseString);
}
Signatureができたので、最後にreturn
してメソッドは完成です。
1-6. 完成したメソッド
public static string ComputeSignature(
HttpMethod httpMethod, string url, string tokenKey, string tokenSecret,
string consumerKey, string consumerSecret, string signatureMethod,
string nonce, string timestamp, string version
)
{
// パラメータ無しのURLを取得
var baseUrl = url;
var getParams = "";
if (url.Contains("?"))
{
var index = url.IndexOf("?");
baseUrl = url.Substring(0, index);
getParams = url.Substring(index + 1);
}
// 必須のパラメータを用意
var paramList = new List<string>()
{
"oauth_token=" + tokenKey,
"oauth_consumer_key=" + consumerKey,
"oauth_signature_method=" + signatureMethod,
"oauth_nonce=" + nonce,
"oauth_timestamp=" + timestamp,
"oauth_version=" + version,
};
// URLのパラメータをparamListに追加
if (!string.IsNullOrEmpty(getParams))
{
foreach (var param in getParams.Split('&'))
{
var parsed = param.Split('=');
if (!string.IsNullOrEmpty(parsed[0]))
{
var name = Uri.UnescapeDataString(parsed[0]);
var value = parsed.Length >= 2 ? Uri.UnescapeDataString(parsed[1]) : "";
if (paramList.Any(x => x.StartsWith(value + "=")))
{
var removeParam = paramList.Where(x => x.StartsWith(value + "=")).FirstOrDefault();
paramList.Remove(removeParam);
}
paramList.Add(name + "=" + value);
}
}
}
// パラメータを昇順に並び替え、&でjoin
paramList.Sort();
var baseParams = string.Join("&", paramList);
var baseString = httpMethod.ToString().ToUpper()
+ "&" + Uri.EscapeDataString(baseUrl)
+ "&" + Uri.EscapeDataString(baseParams);
// HMAC-SHA256で署名を作成
var key = Uri.UnescapeDataString(consumerSecret) + "&" + Uri.UnescapeDataString(tokenSecret);
var signature = "";
var encording = new System.Text.ASCIIEncording();
using (var hmacsha256 = new HMACSHA256(encording.GetBytes(key)))
{
byte[] hashBaseString = hmacsha256.ComputeHash(encording.GetBytes(baseString));
signature = Convert.ToBase64String(hashBaseString);
}
return signature;
}
2. リクエストのHeaderに詰めるAuthenticationを作る
Authenticationを作るためのメソッドを下記の通り作ります。
public static AuthenticationHeaderValue GenerateAuthenticationHeader(
HttpMethod httpMethod, string url
)
{
var tokenKey = "2b0ce516420110bcbd36b69e99196d1b7f6de3c6234c5afb799b73d87569f5cc";
var tokenSecret = "c29a677df7d5439a458c063654187e3d678d73aca8e3c9d8bea1478a3eb0d295";
var consumerKey = "ef40afdd8abaac111b13825dd5e5e2ddddb44f86d5a0dd6dcf38c20aae6b67e4";
var consumerSecret = "d26ad321a4b2f23b0741c8d38392ce01c3e23e109df6c96eac6d099e9ab9e8b5";
var signatureMethod = "HMAC-SHA256";
var nonce = "fjaLirsIcCGVZWzBX0pg"; // 本来は毎回違う値を用意
var timestamp = "1508242306"; // 本来は毎回違う値を用意
var version = "1.0";
var realm = "123456";
var signature = ComputeSignature(httpMethod, url, tokenKey, tokenSecret,
consumerKey, consumerSecret, signatureMethod,
nonce, timestamp, version);
var authString = @"realm=""" + Uri.UnescapeDataString(realm) + @""", " +
@"oauth_token=""" + Uri.UnescapeDataString(tokenKey) + @""", " +
@"oauth_consumer_key=""" + Uri.UnescapeDataString(consumerKey) + @""", " +
@"oauth_nonce=""" + Uri.UnescapeDataString(nonce) + @""", " +
@"oauth_timestamp=""" + Uri.UnescapeDataString(timestamp) + @""", " +
@"oauth_signature_method=""" + Uri.UnescapeDataString(signatureMethod) + @""", " +
@"oauth_version=""" + Uri.UnescapeDataString(version) + @""", " +
@"oauth_signature=""" + Uri.UnescapeDataString(signature) + @"""";
return new AuthenticationHeaderValue("OAuth", authString);
}
3. リクエストを投げる
※このままだと1ページ目しか取れないので、実際はdo-while
文などを使ってください。
public static async Task<string> GetEmployeeAsync(string internalId)
{
var url = "https://123456.suitetalk.api.netsuite.com/services/rest/record/v1/employee/" + internalId;
var httpMethod = HttpMethod.Get;
var content = "";
using (var client = new HttpClient())
{
var request = neww HttpRequestMessage(httpMethod, url);
request.Header.Authorization = GenerateAuthenticationHeader(httpMethod, url);
var response = await client.SendAsync(request);
content = await response.Content.ReadAsStringAsync();
}
return content;
}
content
にPostmanで見たような値が入っていれば成功です。