WooCommerce:安全重定向未登录用户的自定义账户页面端点

WooCommerce:安全重定向未登录用户的自定义账户页面端点

本文详细介绍了如何解决woocommerce中未登录用户意外访问“我的账户”页面及其自定义端点的问题。通过利用`template_redirect`钩子和精确的条件逻辑,教程展示了如何确保只有已登录用户才能访问这些受保护的页面,同时允许“找回密码”等特定页面对未登录用户开放,从而提升网站的安全性和用户体验。

在WooCommerce开发中,有时我们希望“我的账户”页面及其所有子页面(包括自定义端点)仅对已登录用户可见。例如,当网站设计要求登录/注册表单以弹窗形式展示,而非通过默认的“我的账户”页面时,就需要实现这种重定向机制。这不仅关乎用户体验,更是网站安全性的重要组成部分,防止未授权访问敏感信息或功能。

理解问题:未登录用户访问“我的账户”端点

最初的重定向尝试通常会针对“我的账户”主页面进行,但往往忽略了其下方的自定义端点。当用户在未登录状态下直接访问如 my-account/my_returns 这样的自定义端点时,原有的重定向逻辑可能无法生效,导致用户看到不应出现的登录表单或页面内容。

初始重定向逻辑示例(存在局限性):

add_action( 'template_redirect', 'wish_custom_redirect' );

function wish_custom_redirect() {
  global $wp;

  if (
        !is_user_logged_in()
        &&
        ('my-account' == $wp->request) // 仅针对 'my-account' 主页面
        &&
        ('lost-password' != $wp->request) // 排除 'lost-password'
     )
  {
    wp_redirect( home_url() );
    exit;
  }
}
登录后复制

这段代码的问题在于,(‘my-account’ == $wp->request) 这一条件只精确匹配了“我的账户”主页的请求路径。当请求路径是 my-account/my_returns 时,$wp->request 的值会是 my-account/my_returns,与 ‘my-account’ 不匹配,因此重定向不会触发。

WooCommerce自定义端点的创建

为了更好地理解重定向的必要性,我们首先回顾一下WooCommerce中自定义端点的典型创建流程。这个过程涉及添加重写规则、注册查询变量、将端点添加到账户菜单以及为端点添加内容。


Dreamina

Dreamina

字节跳动推出的AI绘画工具,用简单的文案创作精美的图片

Dreamina
449


查看详情
Dreamina

  1. 注册新的重写端点: 使用 add_rewrite_endpoint() 函数为“我的账户”页面添加一个新的URL端点。

    function ts_custom_add_my_returns_endpoint() {
        add_rewrite_endpoint( 'my_returns', EP_ROOT | EP_PAGES );
    }
    add_action( 'init', 'ts_custom_add_my_returns_endpoint' );
    登录后复制
  2. 添加新的查询变量: 注册与端点对应的查询变量,以便WordPress识别。

    function ts_custom_my_returns_query_vars( $vars ) {
        $vars[] = 'my_returns';
        return $vars;
    }
    add_filter( 'woocommerce_get_query_vars', 'ts_custom_my_returns_query_vars', 0 );
    登录后复制
  3. 插入到“我的账户”菜单: 将新端点添加到“我的账户”导航菜单中。

    function ts_custom_add_my_returns_link_my_account( $items ) {
        $items['my_returns'] = 'My returns';
        return $items;
    }
    add_filter( 'woocommerce_account_menu_items', 'ts_custom_add_my_returns_link_my_account' );
    登录后复制
  4. 为端点添加内容: 使用 woocommerce_account_{endpoint_slug}_endpoint 钩子为自定义端点填充内容。

    function ts_custom_my_returns_content() {
        // 在此处添加端点页面的具体内容,例如显示退货订单列表
        ?>
        <h2 class="text-center woocommerce-products-header__title page-title need-title"><?php echo get_theme_mod('my_returns_tab_heading') ?></h2>
        <section class="order">
            <?php
            $orders = wc_get_orders( array(
                'numberposts' => -1,
                'orderby' => 'date',
                'order' => 'DESC',
                'customer_id' => get_current_user_id(),
                'status' => array('refunded','cancelled'),
            ) );
            foreach( $orders as $order ){
                // ... 订单内容展示逻辑 ...
            }
            ?>
        </section>
        <?php
    }
    add_action( 'woocommerce_account_my_returns_endpoint', 'ts_custom_my_returns_content' );
    登录后复制

    注意: 在添加或修改重写规则后,务必访问WordPress后台的“设置” > “固定链接”页面,并点击“保存更改”按钮,以刷新重写规则,否则可能会出现404错误。

解决方案:扩展重定向逻辑以包含自定义端点

要正确地重定向未登录用户对“我的账户”主页面及其所有自定义端点的访问,我们需要更精细的条件判断。关键在于使用逻辑或 (||) 运算符来组合多个页面路径的匹配,同时通过逻辑与 (&&) 运算符确保用户未登录且排除特定页面。

以下是经过优化的重定向代码:

add_action('template_redirect', 'wish_custom_redirect_extended');

function wish_custom_redirect_extended()
{
    global $wp; // 访问全局 $wp 对象,其中包含当前请求的路径

    // 定义需要保护的账户页面端点列表
    // 这里的 'my-account' 是主页,'my_returns' 是一个自定义端点
    // 您可以根据需要添加更多自定义端点,例如 'my_addresses', 'edit-account' 等
    $protected_endpoints = array(
        'my-account',
        'my-account/my_returns', // 示例自定义端点
        // 添加其他需要保护的自定义端点,例如:
        // 'my-account/my_wishlist',
        // 'my-account/orders',
        // 'my-account/edit-account',
        // 'my-account/edit-address',
        // 'my-account/payment-methods',
        // 'my-account/customer-logout', // 通常应允许登出,但如果需要重定向也可以包含
    );

    // 检查当前请求路径是否在受保护的端点列表中
    $is_protected_endpoint = false;
    foreach ($protected_endpoints as $endpoint) {
        // 匹配精确路径或以该路径开头的任何子路径
        // 例如,如果 $wp->request 是 'my-account/orders/view-order/123'
        // 那么 'my-account/orders' 应该匹配
        if (strpos($wp->request, $endpoint) === 0) {
            $is_protected_endpoint = true;
            break;
        }
    }

    // 综合判断是否需要重定向
    if (
        !is_user_logged_in() // 用户未登录
        &&
        $is_protected_endpoint // 且当前页面是受保护的账户页面或其子页面
        &&
        ('lost-password' != $wp->request) // 排除“找回密码”页面
    ) {
        // 使用 wp_safe_redirect() 进行安全重定向到网站首页
        wp_safe_redirect(site_url());
        exit; // 终止脚本执行
    }
}

// 确保用户登出后也重定向到首页,防止返回缓存页面
add_action('wp_logout','auto_redirect_after_logout');
function auto_redirect_after_logout(){
  wp_safe_redirect( home_url() );
  exit();
}
登录后复制

代码解释与最佳实践

  1. $wp->request: 这个全局变量包含了当前请求的干净URL路径(不含域名和查询参数)。它是判断用户访问哪个页面的关键。
  2. !is_user_logged_in(): 这是一个WordPress核心函数,用于检查当前用户是否已登录。
  3. $protected_endpoints 数组和循环:

    • 我们定义了一个数组 $protected_endpoints 来列出所有需要保护的“我的账户”相关路径。这使得代码更易于维护和扩展。
    • 通过循环遍历这个数组,并使用 strpos($wp->request, $endpoint) === 0 来检查当前请求路径是否以任何一个受保护的端点开头。这种方式可以捕获主端点及其所有子端点(例如,my-account 会匹配 my-account、my-account/orders 等)。
  4. (‘lost-password‘ != $wp->request): 这一条件至关重要,它确保“找回密码”页面对未登录用户是可访问的,这是恢复账户的必要功能。
  5. wp_safe_redirect(site_url()):

    • wp_safe_redirect() 是WordPress推荐的重定向函数,它比 wp_redirect() 更安全,因为它会验证重定向URL,防止开放重定向漏洞。
    • site_url() 返回WordPress网站的URL,即重定向的目标地址。
  6. exit;: 在重定向后,务必调用 exit; 来终止脚本的进一步执行,防止在重定向发生后仍然输出其他内容。
  7. wp_logout 钩子: 额外添加的 wp_logout 钩子确保用户在登出后立即被重定向到网站首页,防止他们使用浏览器后退按钮返回到可能包含敏感信息的缓存页面。

实施步骤

  1. 选择放置位置: 将上述优化后的代码片段添加到您的主题的 functions.php 文件中。

    • 推荐做法: 最好将其放置在一个子主题的 functions.php 文件中,这样在更新父主题时不会丢失您的自定义代码。
    • 更专业的做法: 创建一个自定义插件来管理这类功能,这有助于代码的模块化和可移植性。
  2. 测试:

    • 清除网站缓存(如果使用了缓存插件)。
    • 使用不同的浏览器或隐身模式,在未登录状态下尝试直接访问“我的账户”主页 (/my-account/) 和您创建的自定义端点 (/my-account/my_returns/)。
    • 确认这些页面都成功重定向到了网站首页。
    • 测试“找回密码”页面 (/my-account/lost-password/),确保它仍然可以正常访问。
    • 登录后测试,确保已登录用户可以正常访问所有“我的账户”页面和端点。

通过以上步骤和代码,您可以有效地控制WooCommerce中“我的账户”页面及其自定义端点的访问权限,确保只有已登录用户才能查看这些内容,从而提升网站的安全性和用户体验。

以上就是WooCommerce:安全重定向未登录用户的自定义账户页面端点的详细内容,更多请关注php中文网其它相关文章!

https://www.php.cn/faq/1820907.html

发表回复

Your email address will not be published. Required fields are marked *