はじめに
WordPressで独自APIを作ったときなどで、ログインしているユーザーにしか叩いて欲しくないAPIありますよね。
最初は、APIのコードの中でis_user_logged_in()
とかやって、ログインしてなかったら弾けばいいや。と思ってましたが、話はそう簡単ではなかった。
WP REST APIの公式の認証の「クッキー認証」ところを読みましたが、結構ハマったので書いておきます。
ちなみに、ここに書いた方法が正しいかどうかはよくわからないけどね...
独自APIの作り方はこちらを参考にしています。
流れ
APIの中ではユーザーがログインしているかどうかは判定できません。(なんでかは分からんけど)
というわけで、WordPressのnonceを使用して、APIを叩く権限があるかどうかチェックしていきます。
今回は管理画面でのみ使用できるAPIを想定して説明します。
nonceを作成
//管理画面用のcssとjsを読み込む
add_action( 'admin_enqueue_scripts', 'load_custom_wp_admin_style' );
function load_custom_wp_admin_style($hook) {
$apiArgs = [
'root' => esc_url_raw( rest_url() ), //APIのルートURLが入ってます
'nonce' => wp_create_nonce( 'wp_rest' ) //nonceの名前は「wp_rest」にします
];
wp_enqueue_script( 'master-js', plugins_url('master.js', __FILE__), ['jquery'], '1.0');
wp_localize_script( 'master-js', 'WP_API_Settings', $apiArgs );
}
解説
wp_enqueue_script
の第一引数と、wp_localize_script
の第一引数を揃えます。
ここで、どのjsファイルに紐付けるか設定しています。
wp_localize_script
の第二引数WP_API_Settings
は、その名前でオブジェクトを作成しますよと言っています。
wp_localize_script
の第三引数で、オブジェクトに設定したい値を入れています。
今回は、「wp_rest」という名前でnonceを作成しました。
管理画面の対象のページに移動して、ページのソースを表示して、WP_API_Settings
で検索してみてください。
このような感じで変数が出力されていると思います。
変数が出力されていなかったら、どこか間違っていますので修正してください。
nonceをjs側で使用
続いて、JavaScript側に移ります。
$.ajax({
url: WP_API_Settings.root + '/wp/v2/test_api',
type: 'POST',
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', WP_API_Settings.nonce );
},
data: saveData,
})
.done( (data) => {
alert('成功しました')
})
.fail( (data) => {
alert('失敗しました')
})
解説
先程、wp_localize_script
で作成したwp_localize_script
を使用しています。
nonceは、beforeSend
を使ってHTTPのヘッダーとして渡します。
nonceをphp側でチェック
function test() {
$response = new WP_REST_Response();
$nonceResult = wp_verify_nonce($_SERVER['HTTP_X_WP_NONCE'], 'wp_rest');
if(!$nonceResult) {
$response->set_status(403);
return $response;
}
}
解説
wp_verify_nonce
でnonceが正しいかチェックしています。
js側でヘッダーにセットした値は、$_SERVER['HTTP_X_WP_NONCE']
で取得します。
※php側で受け取るときは、なぜかすべて大文字になりますのでご注意。
最初にwp_rest
という名前で、nonceを作成したので、同じ名前でチェックします。
まとめ
だいたいWordPressのAPIといえば、記事の取得とか誰が叩いてもOKなのが多いんですけど、そうでない場合もたまにありました。
全部のAPIが管理者しか叩けないようにしたい場合は、APIのフックがあって、そこで管理者かどうかのチェックを入れるコードもググったら出てきました。
途中で諦めそうになった...