You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress插件Password Protect重定向循环问题,求修复方案

问题定位与修复方案

重定向循环的核心原因

  1. 外部URL被wp_safe_redirect拦截
    WordPress的wp_safe_redirect默认只允许跳转到当前站点域名或已授权的外部域名。如果目标URL是外部站点(比如示例中的https://example.com/a)且未添加到白名单,函数会自动跳转到站点首页,导致插件反复尝试跳转外部URL、又被拦截回首页,形成循环。

  2. URL字符串比较逻辑不严谨
    直接用$redirect_url != $current_url判断,会因以下场景触发误判:

  • URL末尾斜杠差异(如https://example.com/a vs https://example.com/a/)
  • HTTP/HTTPS协议不一致
  • 存在额外查询参数(如https://example.com/a?utm_source=xxx)
  • 带www与不带www的域名差异
  1. is_page函数的局限性
    is_page('password-protect')仅对WordPress管理的页面生效,如果目标URL是本站静态页、自定义路由或外部页面,该判断会返回false,导致插件错误触发跳转逻辑。

修复步骤与代码调整

1. 授权外部跳转域名(针对外部URL场景)

添加过滤器自动从密码映射中提取目标域名,加入安全跳转白名单:

add_filter('allowed_redirect_hosts', function($hosts) {
    global $passwords;
    foreach ($passwords as $url) {
        $parsed = parse_url($url);
        if (isset($parsed['host'])) {
            $hosts[] = $parsed['host'];
        }
    }
    return $hosts;
});

2. 优化URL比较逻辑

新增标准化URL函数,统一处理协议、斜杠、域名格式,避免无意义的差异:

function normalize_url($url) {
    $url = rtrim($url, '/');
    $parsed = parse_url($url);
    if (!$parsed) return '';
    
    $scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : (is_ssl() ? 'https' : 'http');
    $host = isset($parsed['host']) ? strtolower($parsed['host']) : $_SERVER['HTTP_HOST'];
    $path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
    
    return "$scheme://$host$path";
}

3. 替换is_page判断为路径检查

避免依赖WordPress页面检测函数,直接通过URL路径判断是否在密码页:

$password_page_url = normalize_url(site_url('password-protect'));
$is_password_page = ($current_url === $password_page_url);

4. 完整修复后的代码

<?php

$passwords = array(
    'password-a' => 'https://example.com/a',
    'password-b' => 'https://example.com/b',
);

// 自动授权密码映射中的外部域名
add_filter('allowed_redirect_hosts', function($hosts) {
    global $passwords;
    foreach ($passwords as $url) {
        $parsed = parse_url($url);
        if (isset($parsed['host'])) {
            $hosts[] = $parsed['host'];
        }
    }
    return $hosts;
});

// 标准化URL,消除协议、斜杠、域名格式差异
function normalize_url($url) {
    $url = rtrim($url, '/');
    $parsed = parse_url($url);
    if (!$parsed) return '';
    
    $scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : (is_ssl() ? 'https' : 'http');
    $host = isset($parsed['host']) ? strtolower($parsed['host']) : $_SERVER['HTTP_HOST'];
    $path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
    
    return "$scheme://$host$path";
}

function password_protect_init() {
    global $passwords;

    if (is_admin() || is_user_logged_in()) {
        return;
    }

    $current_url = normalize_url((is_ssl() ? "https://" : "http://") . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    $password_page_url = normalize_url(site_url('password-protect'));
    $is_password_page = ($current_url === $password_page_url);

    if (isset($_POST['my_website_password'])) {
        $password = sanitize_text_field($_POST['my_website_password']);
        if (array_key_exists($password, $passwords)) {
            // 增强Cookie安全性,添加SameSite与Secure属性
            setcookie('my_website_password', $password, time() + 86400, '/', '', is_ssl(), true);
            $redirect_url = normalize_url($passwords[$password]);
            wp_safe_redirect($redirect_url);
            exit;
        } else {
            // 密码错误时跳回密码页
            wp_safe_redirect($password_page_url);
            exit;
        }
    }

    if (isset($_COOKIE['my_website_password']) && array_key_exists($_COOKIE['my_website_password'], $passwords)) {
        $redirect_url = normalize_url($passwords[$_COOKIE['my_website_password']]);
        
        // 仅当当前URL不等于目标URL且不在密码页时跳转
        if ($current_url !== $redirect_url && !$is_password_page) {
            wp_safe_redirect($redirect_url);
            exit;
        }
    } elseif (!$is_password_page) {
        wp_safe_redirect($password_page_url);
        exit;
    }
}
add_action('wp', 'password_protect_init', 10);

function password_protect_template_redirect() {
    $password_page_path = parse_url(site_url('password-protect'), PHP_URL_PATH);
    $current_path = parse_url((is_ssl() ? "https://" : "http://") . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
    
    if ($current_path === $password_page_path) {
        ?>
        <html>
        <head>
            <title>Password Protected</title>
        </head>
        <body>
            <form method="post">
                <label for="my_website_password">Password:</label>
                <input type="password" id="my_website_password" name="my_website_password">
                <input type="submit" value="Submit">
            </form>
        </body>
        </html>
        <?php
        exit;
    }
}
add_action('template_redirect', 'password_protect_template_redirect');

function password_protect_login_redirect($redirect_to) {
    if (!isset($_GET['redirect_to']) || $_GET['redirect_to'] == 'wp-admin/') {
        $redirect_to = site_url('password-protect');
    }
    return $redirect_to;
}
add_filter('login_redirect', 'password_protect_login_redirect');

额外优化建议

  • 添加密码错误提示:在密码页显示错误信息,提升用户体验
  • 限制密码尝试次数:防止暴力破解
  • 支持多语言:将密码页文本改为可翻译字符串

内容的提问来源于stack exchange,提问作者Noel Bürgler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 02:47:03