WordPressで認証導線を作ったら ERR_TOO_MANY_REDIRECTS になった話(if切り分け+404返却で解決)
他の言語のログイン画面より、トークンを受け取ったらwordpress側のフロントエンドを見せる仕組み
wordpress自体のログイン機能は使わない。
リダイレクト多くてエラーを繰り返してしまいます。
外部のログイン画面(アプリ/別実装)から ?token=xxxx を付けて WordPress に遷移し、以後は Cookie(__session)を鍵にして閲覧可否を判定する仕組みを作っていました。
ところが実装途中で ERR_TOO_MANY_REDIRECTS(リダイレクトが多すぎる) を踏みました。
結論としては、
- **if文の切り分け(処理順の整理)**で無限ループを止める
-
未認証時は「別URLにリダイレクト」ではなく、WordPress側で 404 を返す(= その場で404テンプレを表示)で安定しました。
(#/webviewのような hash はサーバー側に届かないので、WordPressからは常に/login/にしか見えない、という落とし穴もありました )
なぜ無限リダイレクトになるのか
典型的にはこういう流れになります。
- 初回だけ
/?token=xxxxでアクセス - WordPress側が「未認証」判定 →
/login/にリダイレクト - リダイレクト先には token が付かない(ヘッダーも付かない)ので、また未認証
-
/login/にまたリダイレクト…を繰り返し、ERR_TOO_MANY_REDIRECTS
つまり **「token を cookie に変換する前に redirect してしまっている」**のが致命傷でした
解決方針:ifの切り分け(処理順を固定)
- token が来たら最優先で cookie 化(この前に未認証リダイレクトを書かない)
-
/login等は 認証リダイレクト対象から除外(ループ防止) - 以後の認証判定は cookie だけ
さらに安定させる:未認証時は「リダイレクト」ではなく「404を返す」
今回の最終判断がここでした。
未認証ユーザーを「ログイン画面へ飛ばす」運用にすると、
- 設計や環境によっては
/login/側でまた判定が走る - WebView等で Cookie が保持されないケースだと、永遠に未認証のまま
となって、再発しやすいです(Cookie保持問題が絡むと特に)
そこで、未認証で見せたくないページは “存在しない扱い(404)” にする方針にしました。
リダイレクトではなく その場で 404 ヘッダー+404テンプレを返すので、ループの余地が減ります。
実装例(そのまま使える)
※
is_page('mypage')の部分は、保護したいページ条件に合わせて変更してください。
<?php
// functions.php など
add_action('template_redirect', function () {
$uri = $_SERVER['REQUEST_URI'] ?? '';
// 404 を返す共通処理(今回使ったやつ)
$return_404 = function () {
status_header(404);
nocache_headers();
include get_404_template();
exit;
};
/*
* 1) token が来たら最優先で cookie に変換
* (ここより前に「未認証なら〜へリダイレクト」を書かない)
*/
if (!empty($_GET['token']) && empty($_COOKIE['__session'])) {
setcookie('__session', (string) $_GET['token'], [
'expires' => time() + 60 * 60 * 24 * 7,
'path' => '/',
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Lax',
]);
// token をURLから消してクリーンに
wp_safe_redirect(remove_query_arg('token'));
exit;
}
/*
* 2) /login は除外(ここが無いとループしやすい)
* ※ #/webview などの hash はサーバーに届かないので URL文字列で判定する
*/
if (preg_match('~^/login/?($|\?)~', $uri)) {
return;
}
/*
* 3) ここから cookie で認証判定
* 未認証なら「リダイレクト」ではなく「404を返す」
*/
if (is_page('mypage')) {
if (empty($_COOKIE['__session'])) {
$return_404();
}
}
});
この構成にして良かった点
- リダイレクトループが起きにくい(未認証時に別URLへ飛ばさない)
- 「保護ページの存在」を未認証ユーザーに見せない(404扱い)
- token は初回だけ消費して cookie に変換し、以後は cookie だけで判定できる