WordPress へのアクセス制限を functions.php で設定する

WordPress へのアクセス制限を functions.php で設定する

獣電戦隊キョウリュウジャーVSゴーバスターズ 恐竜大決戦!さらば永遠の友よ』はとてもよい映画でしたね!闇の底から杖を投げるバンドーラ様には涙せずにいられない世代です。こんにちは kagata です。

今回は、 WordPress テーマファイルの functions.php をカスタマイズすることで、フロント画面へのアクセス制限を設定する方法について考えます。接続元の IP アドレスにより制限するなど、かんたんな条件であれば Web サーバの設定( .htaccess とか)でも実現できますし、サーバーの負荷も小さくなるかもしれません。が、 WordPress 側で設定する方法を知っておくと、 Web サーバー側では対応できないようなきめ細かい条件でのアクセス制限が実現できるようになります。

例えば、こんな状況:

  • WordPress と同一のサーバー上に、連携する外部アプリがある(過去記事を参照:WordPressの投稿データをJSON形式で外部アプリに渡す
  • 外部アプリは認証機能を持っていて、ログインしてきたユーザーにのみ WordPress の「投稿」データを見せる
  • なので、 WordPress に直接アクセスしてきたユーザーには「投稿」データを見せないようにしたい
  • でも、固定ページは WordPress に直接表示させたい

ややこしいですね。今回はこの要件を functions.php のカスタマイズで実現します。

ステップ1:とりあえずアクセスできないようにする

まずは細かい条件を抜きにして、とりあえずアクセスを拒否するコードをみてみます。

add_action('init', 'access_restriction');
function access_restriction() {
	if (is_admin()) {
		return;
	}
	wp_die('だめよだめよだめなのよ', 'だめ', array('responce' => 403));
}

これを有効なテーマの functions.php にコピペすると、フロントのどの画面にアクセスしても次のような表示になるはずです。

wp_die.png

島田一の介の名台詞とともに、アクセスを拒否されました。

アクセスの拒否には関数 wp_die() を使うとよいでしょう。第1引数は画面に表示するメッセージ、第2引数はページのタイトル、そして第3引数のオプションで HTTP 応答のステータスコードを指定しています。ステータスコードの指定を省略すると ステータスコード500 "Internal Server Error" が返るようです。これでもアクセス制限自体はできてしまうのですが、制限の趣旨に応じて403 "Forbidden" なり404 "Not Found" なりを適切に返してやるとお行儀がよいですね。

3行目からの条件分岐は、管理画面を制限対象から外すためのものです。これがないと、テーマファイルを更新した瞬間にフロント画面だけでなく管理画面にも入れなくなってしまいます。

これで、とりあえずアクセス制限のしくみはできました。次は、ここにアクセス許可の条件分岐を加えていきます。

ステップ2:ローカルホストからのアクセスを許す

同一サーバー上の外部アプリからのアクセスは許し、それ以外からのアクセスは拒否するための設定を加えます。

PHP では、自分自身の IP アドレスが $_SERVER['SERVER_ADDR'] に格納されています。また、接続元の IP アドレスは $_SERVER['REMOTE_ADDR'] に格納されています。この2つを比較して一致しなければ、自分自身のいるサーバー以外からのアクセスとみなして拒否しましょう。

add_action('init', 'access_restriction');
function access_restriction() {
	if (is_admin()) {
		return;
	}
	if ($_SERVER['SERVER_ADDR'] != $_SERVER['REMOTE_ADDR']) {
		wp_die('だめよだめよだめなのよ', 'だめ', array('responce' => 403));
	}
}

これで、同一サーバーからのアクセス以外を拒否するようになりました。もちろん、 $_SERVER['REMOTE_ADDR'] の部分を所定のIPアドレスに書き換えてやれば、同一サーバーに限らず任意の接続元からのアクセスを許可・拒否することもできます。

ここまでは、 Web サーバーの設定でも実現できそうな基本的なアクセス制限をご紹介しました。次からが、 WordPress ならではの応用的なアクセス制限です。

ステップ3:ログイン済みユーザーのアクセスを許す

上のコードでアクセスを制限すると、当たり前ですが開発者自身もフロントページを見ることができなくなってしまいます。開発作業のためにフロントページを見たい場合は、以下のようにすると便利です。

add_action('init', 'access_restriction');
function access_restriction() {
	if (is_admin() || is_user_logged_in()) {
		return;
	}
	if ($_SERVER['SERVER_ADDR'] != $_SERVER['REMOTE_ADDR']) {
		wp_die('だめよだめよだめなのよ', 'だめ', array('responce' => 403));
	}
}

関数 is_user_logged_in() を使って、ログイン済みのユーザーにはアクセス制限を適用しないようにしました。これで、見えないはずのコンテンツも WordPress にログインしさえすれば見えるようになる、デバッグモードのようなものを手軽に実現できます。

ステップ4:さらに細かいアクセス条件を指定する

さらに、「投稿は同一サーバーからしか見えないけど、固定ページはふつうに見せたい」なんて場合には、次のようにします。

add_action('wp', 'access_restriction');
function access_restriction() {
	if (is_admin() || is_user_logged_in() || 'page' == get_post_type()) {
		return;
	}
	if ($_SERVER['SERVER_ADDR'] != $_SERVER['REMOTE_ADDR']) {
		wp_die('だめよだめよだめなのよ', 'だめ', array('responce' => 403));
	}
}

3行目の条件分岐で、投稿タイプを比較するようにしました。

なお、この例ではアクセス制限を実施するアクションフックをこれまでの 'init' から 'wp' に変更しています。こうすることで、投稿タイプやカテゴリーなどの情報をかんたんに取得することができるようになり、いろいろな条件判定をシンプルに記述できます。腕に自信のある方は、もっと手前のアクションフックで条件判定しても OK かも。

あとはこの要領で、「このスラッグの投稿は見せるけどあのスラッグの投稿は見せない」「このカテゴリーとこのカテゴリーはいいけどあのカテゴリーはだめ」「カスタム投稿タイプをたくさん作って、投稿タイプごとにゴニョゴニョ」など、いくらでもマニアックなアクセス制限を実現できます(するかどうかは別として)。

まとめ

  • 関数 wp_die() を使って WordPress から403を返そう
  • 自分自身の IP アドレスは $_SERVER['SERVER_ADDR'] を、接続元の IP アドレスは $_SERVER['REMOTE_ADDR'] を参照しよう
  • 関数 is_user_logged_in() はデバッグにも便利
  • アクセス制限は init アクションフックで。細かい条件分岐をかんたんに設定したいなら wp アクションフックもアリ
  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ