是否可以添加使用 WooCommerce 授权的新 API 端点?

Is it possible to add a new API endpoint that uses WooCommerce's authorization?

我需要在我的 WordPress 插件中添加一个 API 端点,它将写入数据库等。我希望它由调用这个新 API 的远程系统触发。

但是,我想使用内置的 WooCommerce REST 身份验证,这里设置的身份验证:

(不,这些凭据不再有效)。

有办法吗?要添加将使用 WooCommerce 的身份验证的自定义 HTTP 端点,然后 运行 我想要的一些任意代码 运行?

或者有没有一种方法可以在现有 WooCommerce API 端点上添加一个钩子到 运行 端点执行之前?我只需要一种方法来使用现有的 WooCommerce REST API 身份验证来触发我需要在我的插件中 运行 的一些更新。

您可以在 Woocommerce 端点下添加路由以使用此 key/secret 身份验证系统。

这是一个工作示例:

add_action('rest_api_init', function () {
    register_rest_route('wc', '/test', [
        'methods'  => 'GET',
        'callback' => 'my_awesome_func',
    ]);
});

function my_awesome_func(WP_REST_Request $request)
{

    if (is_user_logged_in() && (int)wp_get_current_user()->ID === 123) {
        //your stuff only for legged in user 123
        return new WP_REST_Response('ok', 200);
    }

    return new WP_Error('unauthorized', __('You shall not pass'), [ 'status' => 401 ]); //can also use WP_REST_Response

 }

这将:

  • 在“wc”端点(woocommerce one)下添加一个新的 GET 路由,所以 https://example.com/wp-json/wc/test
  • 然后您使用“HTTP Basic auth”根据 Woocommerce documentation
  • 传递您的密钥和秘密
  • is_user_logged_in()wp_get_current_user() 的结果将取决于 key/secret 的正确组合。如果正确,关联的用户将被“认证”为 Wordpress。
  • 如果组合正确,你会得到 [true, WP_user_object],如果组合不正确,你会得到 [false, Empty_user_object]
  • 如果正确的密钥和不正确的秘密,将抛出 401(不是我示例中的那个,是 woocommerce 的另一个 401。在这种情况下未达到 my_awesome_func()。我相信这就像 wp-login,正确登录(密钥)时的自定义错误消息,很好 ^^')

然后您需要按照您的规则保护您的路线:

  • if(!is_user_logged_in()) return false
  • 一样检查用户是否登录
  • 正在检查用户 ID wp_get_current_user()->ID
  • 正在通过您的 role/permission 系统检查
  • 现在你有了用户 ID,你可以用它做你想做的事
  • 使用 WP_REST_Request $request 参数处理 GET 或 POST HTTP 参数。

所以它看起来像:

add_action('rest_api_init', function () {
    register_rest_route('wc', '/test', [
        'methods'  => 'GET',
        'callback' => 'my_awesome_func',
    ]);
});

function my_awesome_func(WP_REST_Request $request)
{

    if (is_user_logged_in() && (int)wp_get_current_user()->ID === 123) {
        //your stuff only for legged in user 123
        return new WP_REST_Response('ok', 200);
    }

    return new WP_Error('unauthorized', __('You shall not pass'), [ 'status' => 401 ]); //can also use WP_REST_Response
}

似乎可以 添加 Woocommerce REST API 端点(找不到关于它的适当文档...)。但我对此进行了测试并且它有效,至少可以使用 Woocommerce key/Secret 身份验证系统,我相信它是在 /wc/ 端点下应用的。

注意:小心地将路由添加到 wc 端点,因为您可能会覆盖现有的路由端点。例如:添加 /product/mytest 可能与处理 /product/[product_id].

的官方 Woocommerce 路由冲突

注2:我先用一个custom WordPress REST API route, and passing Woocommerce key/secret to see if WordPress could see me correctly authenticated and identified. But it didn't work (WP uses the core API auth system)进行了测试。所以我搬到了 Woocommerce API 端点。

注意 3:您可以使用带有自定义路由的 Wordpress REST API 和“机器对机器”身份验证插件(如 Oauth、应用程序密码、JWT...)实现相同的效果,如 WP REST API authentication documentation page.

有点晚了,但通过反射我们可以使用 WC 身份验证逻辑来​​验证自定义 API 路由。

add_action( 'rest_api_init', function () {
    /**
     * Register here your custom routes for your CRUD functions
     */
    register_rest_route( 'test/', 'wc-permissions', array(
        array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => 'read_check',
            'permission_callback' => 'do_wc_basic_auth_permission_check'
        ),
        array(
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => 'write_check',
            'permission_callback' => 'do_wc_basic_auth_permission_check',
        ),
    ) );
} );

/**
 * Perform check via official WC REST auth class by reflecting method accessibility.
 * Uses official auth class, so it triggers all hooks as on normal 'wp-json/wc/v3/' routes
 *
 * @return bool
 * @throws ReflectionException
 */
function validate_request_has_valid_wc_api_keys(): bool {
    // WC not enabled, target reflection class is probably not registered
    if ( ! function_exists( 'WC' ) ) {
        return false;
    }

    $method = new ReflectionMethod( 'WC_REST_Authentication', 'perform_basic_authentication' );
    $method->setAccessible( true );

    return $method->invoke( new WC_REST_Authentication ) !== false;
}

function write_check() {
    return 'can create new entry via POST';
}

function read_check() {

    return 'can get entry content via GET';
}

如果您想将此身份验证检查添加到全局其他路由,f.e。核心 WP 路由,您可以使用 add_filter('rest_dispatch_request', function ( $intendedResponse, $request, $route ) 过滤器并尝试将传递的 $route 参数与正则表达式或其他方式匹配。

只需投入我的两分钱...

我想知道是否有另一种方法可以添加一个新的 API 端点,它使用 WooCommerce 消费者密钥和秘密授权,避免与 WooCommerce /wc/ 端点可能发生的冲突,并且不求助于使用反射。

答案在WC_REST_Authentication class 中包含的is_request_to_rest_api 函数中。为了使用 WooCommerce 身份验证方法,third-party 插件的端点命名空间应以 wc-.

开头

例如:

add_action( 'rest_api_init', function() {
  register_rest_route(
    'wc-myprefix/v1',
    '/orders/(?P<order_id>\d+)/shipment-trackings',
    array(
      'methods'             => WP_REST_Server::READABLE,
      'callback'            => 'get_shipment_trackings',
      'permission_callback' => 'check_permission',
    ),
  );
});

function get_shipment_trackings( WP_REST_Request $request ) {
    // return shipment trackings
}

function check_permission() {
    if ( ! current_user_can( 'read_private_shop_orders' ) ) {
        return new WP_Error( 'woocommerce_rest_cannot_view',
            __( 'Sorry, you cannot list resources.', 'myprefix' ),
            array( 'status' => rest_authorization_required_code() ) );
    }
    return true;
}

请注意新路由的wc-myprefix/v1命名空间(以wc-开头),以及权限回调中current_user_can函数的使用。触发实际身份验证的是对此函数的调用。

如果您像我一样不想让任何人告诉您端点命名空间应该如何命名,那么可以使用一个方便的过滤器 (woocommerce_rest_is_request_to_rest_api) 来实现您自己的逻辑确定调用是否为休息 API 端点(即检查您自己的特定端点命名空间)。