C# で Wordpress の OAuth 認証をする
Wordpress の REST API を C# から叩くため、OAuth 認証をしてアクセストークンを取得します。
プラグインのインストール
OAuth 認証をするためには、Wordpress に以下の plugin をインストールします。
プラグインの検索では出てこないため、github から zip をダウンロードしてきてインストールする必要があります。
WP REST API - OAuth 1.0a Server
https://github.com/WP-API/OAuth1
OAuth 2.0 認証ができるプラグインもあるようですが、今回は公式から出ている 1.0a のものを使います。
Client Key と Client Secret を作成する
プラグインをインストールすると、「ユーザ」ところに「Application」という項目が出てきます。
ここで Client Key と Client Secret を作成します。
Callback は必須だったので、適当な URL を入れています。
"Save Consumer" をすると Client Key と Client Secret が作成されます。
OAuth 認証をする
ここからは C# のクライアント側の処理になります。
Google 製の OAuthBase.cs を利用するのでプロジェクトに追加しておいてください。
公式サイトからは消えてしまっているようでしたが、ぐぐるといくつか出てきます。
追加した際、System.Web を参照に加えておかないと HttpUtility でエラーになります。
OAuth 認証は
- リクエストトークンの取得
- 認証
- アクセストークンの取得
の3段階にわかれているので、順番に行っていきます。
それぞれのエンドポイント URL は http://vccw.dev/wp-json/ にアクセスすると以下のように出てきます。
逆に、authentication が空になっている場合は OAuth プラグインが有効になっていません。
リクエストトークンの取得
class OAuthSample
{
static readonly string CLIENT_KEY = "v9T4twiheMxl";
static readonly string CLIENT_SECRET = "qZccFO1eVR1EndpnHZhqRkT98Y5u6rPGylnvjskFMA46bLL5";
static readonly string BASE_URL = "http://vccw.dev/";
static readonly string REQUEST_URL = BASE_URL + "oauth1/request";
static readonly string AUTHORIZE_URL = BASE_URL + "oauth1/authorize";
static readonly string ACCESS_TOKEN_URL = BASE_URL + "oauth1/access";
public void Authentication()
{
var oauth = new OAuthBase();
var nonce = oauth.GenerateNonce();
var timestamp = oauth.GenerateTimeStamp();
string normalizedUrl, normalizedReqParams;
var signature = oauth.GenerateSignature(
new Uri(REQUEST_URL),
CLIENT_KEY,
CLIENT_SECRET,
null,
null,
"GET",
timestamp,
nonce,
out normalizedUrl,
out normalizedReqParams);
var requestTokenUrl = normalizedUrl + "?" + normalizedReqParams + "&oauth_signature=" + signature;
var client= new WebClient();
var token = Encoding.ASCII.GetString(client.DownloadData(requestTokenUrl ));
}
}
CLIENT_KEY と CLIENT_SECRET から signature を計算し、必要なパラメータとともにリクエストトークンのエンドポイントへ投げます。
パラメータ文字列も OAuthBase.cs 内で勝手に作ってくれます。
得られた token がリクエストトークンで以下のような文字列になっています。
oauth_token=tyNCKaL3WAJXib5SI6jCnr4P&oauth_token_secret=1GiImP2XBacmk4FhcEFtqqENs3Bt6Q1m3zDf5s0Rk2kDJyTF&oauth_callback_confirmed=true
このままでは使いにくいので、適当にパースして oauth_token と oauth_token_secret の値を取っておきます。
認証
得られた oauth_token と oauth_token_secret を使って認証をします。
class OAuthSample
{
static readonly string BASE_URL = "http://vccw.dev/";
static readonly string AUTHORIZE_URL = BASE_URL + "oauth1/authorize";
public void Authentication()
{
...
var auth_url = AUTHORIZE_URL +
"?oauth_token=" + tokenParam["oauth_token"] +
"&oauth_token_secret=" + tokenParam["oauth_token_secret"];
System.Diagnostics.Process.Start(auth_url);
}
}
oauth_token と oauth_token_secret から作成した URL にブラウザでアクセスします。
すると以下のような画面にが出てくるので "Authorize" を押します。
Authorize すると以下のように認証トークンが取得できます。
アクセストークンの取得
得られた認証トークンを使ってアクセストークンを取得します。
GET リクエストでもできると思うのですが、何故か手元の環境ではパラメータが正しく認識されなかったので POST でリクエストを投げています。
しばらくハマりましたが、signature は URL エンコードしておかないと + が消えてエラーになるので注意。
class OAuthSample
{
static readonly string BASE_URL = "http://vccw.dev/";
static readonly string ACCESS_TOKEN_URL = BASE_URL + "oauth1/access";
public void Authentication()
{
...
signature = oauth.GenerateSignature(
new Uri(ACCESS_TOKEN_URL),
CLIENT_KEY,
CLIENT_SECRET,
tokenParam["oauth_token"],
tokenParam["oauth_token_secret"],
"POST",
timestamp,
nonce,
verification_token,
out normalizedUrl,
out normalizedReqParams
);
var params = normalizedReqParams + "&oauth_signature=" + HttpUtility.UrlEncode(signature);
var ps = new NameValueCollection();
foreach(var param in params.Split('&'))
{
var data = param.Split('=');
ps.Add(data[0], data[1]);
}
var access_token = client.UploadValues(ACCESS_TOKEN_URL, ps);
}
}
問題なくリクエストが通れば、以下の様な形式でアクセストークンが取得できます。
oauth_token=tNo6uEm22jk3VplA7QQ1D1B7&oauth_token_secret=XVPdQboBzGfFXelXIzfVWQpY0Ox8YDTivbjHcv3Kgj0tD8vM
これで OAuth 認証は完了です。
以降はこのアクセストークンを使ってリクエストが投げられます。
アクセストークンを使って REST API を叩く
アクセストークンを使って Wordpress に新規投稿をしてみます。
class OAuthSample
{
static readonly string CLIENT_KEY = "v9T4twiheMxl";
static readonly string CLIENT_SECRET = "qZccFO1eVR1EndpnHZhqRkT98Y5u6rPGylnvjskFMA46bLL5";
static readonly string ACCESS_TOKEN = "tNo6uEm22jk3VplA7QQ1D1B7";
static readonly string ACCESS_TOKEN_SECRET = "XVPdQboBzGfFXelXIzfVWQpY0Ox8YDTivbjHcv3Kgj0tD8vM";
static readonly string BASE_URL = "http://vccw.dev/";
static readonly string REST_URL = BASE_URL + "wp-json/wp/v2/";
static readonly string POST_URL = REST_URL + "posts/";
public void PostRequest()
{
var oauth = new OAuthBase();
var nonce = oauth.GenerateNonce();
var timestamp = oauth.GenerateTimeStamp();
string normalizedUrl, normalizedReqParams;
var sign = oauth.GenerateSignature(
new Uri(post_url),
CLIENT_KEY,
CLIENT_SECRET,
ACCESS_TOKEN,
ACCESS_TOKEN_SECRET,
"POST",
timestamp,
nonce,
out normalizedUrl,
out normalizedReqParams);
var header = $"OAuth oauth_consumer_key=\"{CLIENT_KEY}\", "
+ $"oauth_nonce=\"{nonce}\", "
+ $"oauth_signature=\"{HttpUtility.UrlEncode(signature)}\","
+ $"oauth_signature_method=\"HMAC-SHA1\","
+ $"oauth_timestamp=\"{timestamp}\", "
+ $"oauth_token=\"{ACCESS_TOKEN}\", "
+ $"oauth_version=\"1.0\"";
client.Headers[HttpRequestHeader.Authorization] = header;
client.Encoding = Encoding.UTF8;
client.Headers[HttpRequestHeader.ContentType] = "application/json;charset=UTF-8";
client.Headers[HttpRequestHeader.Accept] = "application/json";
var client = new WebClient();
var responce = client.UploadString(POST_URL, "{\"title\":\"test post\", \"status\":\"publish\"}");
}
}
Authentication ヘッダが長くて面倒ですが、こんな感じで使います。